57 Commits
Author SHA1 Message Date
fred 0f55fc23f3 feat: alpha-6, lots of feat and fix 2026-03-15 10:29:17 +01:00
fred fa533a0a2d fix: debug exception display 2026-03-08 18:31:01 +01:00
fred 5ddbd73146 fix: string #hexa escaping, debug local variables, SUBR updated si offset
feat: gened.w test program
2026-03-08 12:11:44 +01:00
fred 80847f4993 feat: lex mod, sortedsearch function
fix: dynIns bug (value in empty attribute), typeof mode
WIP varptrtbl
2026-03-07 18:26:27 +01:00
fred 1fe89c0b6a feat: delete done on hash members
fix: end of line comment formating
2026-02-22 19:13:22 +01:00
fred ddbbb29038 feat: hash.count
fix:DELE woth PVAR, todo with hash
2026-02-21 21:02:07 +01:00
fred eca0605104 feat: foreach numeric, @var oid level, free deleted 2026-02-21 16:06:54 +01:00
fred 72f749172f fix: encod lib Base64 + hash MD5 2026-02-15 13:18:12 +01:00
fred 5c58e7ba97 WIP encod Mod 2026-01-31 11:53:26 +01:00
fred c036ec478c feat: LZW ok with GIF files 2026-01-25 17:23:43 +01:00
fred a23c183f7d WIP socket 2026-01-24 20:38:40 +01:00
fred dc02ac4243 WIP lock 2026-01-24 18:52:46 +01:00
fred 280b10ca99 WIP process & socket 2026-01-18 15:56:38 +01:00
fred db24144e31 feat: debug and quit message on PROG/BACK programs, linux and windows 2026-01-11 18:59:09 +01:00
fred efd1b9a91d feat: ident check and signal/event 2026-01-02 10:56:49 +01:00
fred 33d9ca87c0 fix: debug + copy_nom 2025-12-28 16:38:13 +01:00
fred 4983647ad1 fix: srcdbg 2025-12-27 20:03:35 +01:00
fred dea729767e fix: file source line + debug + sdbg 2025-12-27 18:58:06 +01:00
fred aa61937a20 WIP source line number management 2025-12-25 18:21:33 +01:00
fred 01113671ec WIP src line number management 2025-12-21 18:15:44 +01:00
fred 68d3311b01 fix: object management + this/parent pseudo vars ok + include search for srcdbg 2025-12-21 15:14:29 +01:00
fred 55ad7180e1 fix: pdf time TU 2025-12-14 12:13:43 +01:00
fred a2505eabf7 feat: pdfMod 2025-12-14 12:08:45 +01:00
fred 2ad1bada78 feat: debug background process WIP pdf mod 2025-12-13 17:14:35 +01:00
fred 8460963bc3 WIP shell compilation 2025-12-06 20:21:58 +01:00
fred 4cbc937c45 WIP compilation, debug 2025-12-06 20:20:49 +01:00
fred f60884882c fix: compilation + assemblage 2025-11-30 20:06:45 +01:00
fred 2a07637008 WIP debug background process 2025-11-30 18:48:54 +01:00
fred 6f207a7ed4 WIP namedpipe 2025-11-29 18:32:44 +01:00
fred 2ffcab88b3 WIP 2025-11-29 18:05:15 +01:00
fred a3cc520837 WIP refactoring 2025-11-23 17:43:17 +01:00
fred 22de8f85c5 WIP refactoring #define enum 2025-11-23 17:35:58 +01:00
fred 7019ea7f8b Merge branch 'dev/alpha-4' of https://git.lanisys.fr/lanisys/W into dev/alpha-4 2025-11-23 10:36:57 +01:00
fred 799c7c7548 fix: ticket #1 2025-11-23 10:36:46 +01:00
fred 961994d6c7 Actualiser README.md 2025-11-16 18:58:43 +01:00
fred f8f63d87d4 Actualiser README.md 2025-11-16 18:57:37 +01:00
fred 3384b0df85 feat: arg management in lw lwa lwc 2025-11-16 18:24:08 +01:00
fred fcb62ff71c eat: pdfMod + gestion des arguments en ligne de commande 2025-11-16 16:40:04 +01:00
fred 0871ed56fc WIP divers / shm 2025-10-25 18:42:27 +02:00
fred a6f8d2aefa WIP 2025-09-28 17:56:10 +02:00
fred ba010944e2 WIP fn mod, shmMod 2025-09-28 17:36:18 +02:00
fred 2b076ebd18 WIP pdfMod + revoir le test des fonctions 2025-09-27 21:20:21 +02:00
fred 7cdd94920e WIP modPdf 2025-09-14 19:46:07 +02:00
fred 764752c3c5 feat: real 0.2 2025-09-13 19:08:41 +02:00
fred 84548796b2 WIP unassemble instruction during tracing 2025-08-31 15:23:31 +02:00
fred eb4a60f1e5 feat: module pdf 2025-08-24 20:03:32 +02:00
fred 523a925d0c feat: maj buffer pour message queue 2025-08-23 18:50:54 +02:00
fred 5967052eef fix: lex rules in program, trace display 2025-08-17 18:41:18 +02:00
fred 592298a3df WIP gestion _bin _binaddr _srcdbg avec library 2025-08-17 15:58:41 +02:00
fred a0cf21e3aa WIP 2025-08-16 20:15:12 +02:00
fred c051bfa423 WIP 2025-08-02 18:53:48 +02:00
fred 150697206a feat: modLzw ok et optimise 2025-07-19 19:06:38 +02:00
fred dde78f169b WIP gestion utf8 + lzw 2025-07-19 16:53:31 +02:00
fred bc4be93744 feat: add feat debug mode + lex files 2025-05-11 18:44:57 +02:00
fred dd6f3ebbcf feat: affichage nom fichier + ligne source en cours + compatibilite Windows 2025-05-11 16:52:19 +02:00
fred 3ae1e8c019 feat: json mod 2025-05-08 15:47:59 +02:00
fred 31acb7939d WIP Windows + test READ.md convert from DokuWiki 2025-05-04 19:02:04 +02:00
67 changed files with 11587 additions and 4295 deletions

No files matched your search

+39 -3
View File
@@ -30,6 +30,9 @@ var pour la shared lib, puis exécution :
```
export LD_LIBRARY_PATH=/home/fde/dev/langage/w/exec
(sur le serveur de dev. pour que ce soit compatible avec la version installee)
sudo ln -s /home/fde/dev/langage/w/lex /etc/wlanguage
exec/lw -t -WBIN:./exec -WSRC:. test
```
@@ -40,10 +43,43 @@ ldd
objdump/readelf (moins bien)
cat /proc/*/maps et faire des grep pour voir les .so et module chargés par opendl
```
# Compilation
# Compilation et execution
```
# exec/lwc $1.w $1.wa < $1.w ; exec/lwa $1.wa ; exec/lw $1
exec/genw $1.w && exec/lwa $1.wa ; exec/lw $1
exec/genw $1.w && exec/lwa $1.wa && rm $1.wa && exec/lw $1
```
# Site Web
https://www.lanisys.fr/wiki/doku.php?id=w
https://w.lanisys.fr/
## LANGAGE W
### Présentation
Le but du langage W est d’être simple, efficace, robuste.
Il est fourni avec un compilateur qui génère un code binaire de type
*p-code*, compatible toute plateforme.
Un exécuteur de p-code W sera disponible sur Linux et d’autres OS.
Un interpréteur W permet également d’exécuter un programme W en mode
*script*.
Un module FastCGI permettra de plus d’utiliser le langage W en mode
interprété ou compilé pour les sites Internet.
Enfin, les programmes W pourront être appelés depuis d’autres
programmes, un peu comme un langage de plugins.
Deux utilitaires permettent de formatter le code source et de générer de
la documentation à partir de *tags* dans le code, au format
[DokuWiki](https://www.dokuwiki.org/dokuwiki).
Description du fonctionnement des [programmes](/w/prog) d’exécution et
compilation.
Pour démarrer, premier programme d’exemple :
``` w
; Le celebre Hello world en W
begin hello
echonl "Hello world !"
except
end
```
Voici la description complète du [langage W](/w/instr).
+34
View File
@@ -0,0 +1,34 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#undef WAPIDECL
#define WAPIDECL
// for windows compilation and generating/using import library
#ifdef WAPIEXPORT
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#endif
#ifdef WAPIIMPORT
#undef WAPIDECL
#define WAPIDECL __declspec(dllimport)
#endif
+55
View File
@@ -0,0 +1,55 @@
#define ARG_DEBUG "d"
#define ARG_TRACE "t"
#define ARG_DISASM "d"
void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
{
int nbOpt = 0, cpt = 0, clc = 0;
dynSetLen(e, arg, 0);
dynStoreSz(e, arg, 6, ++clc, argv[0], DYN_LGNONE, cFM, cVM);
for(int a = 1; a < argc; a++)
{
dynStoreSz(e, arg, 6, ++clc, argv[a], DYN_LGNONE, cFM, cVM);
//
if(strcmp(argv[a], "-" ARG_DEBUG) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_DEBUG, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_TRACE) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_TRACE, 1, cFM, cVM);
else if(strncmp(argv[a], "-WBIN:", 6) == 0 && strlen(argv[a]) > 6)
dynStoreSz(e, arg, 3, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.o .so)
else if(strncmp(argv[a], "-WLIB:", 6) == 0 && strlen(argv[a]) > 6)
dynStoreSz(e, arg, 5, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.wp .wa)
else if(strncmp(argv[a], "-WSRC:", 6) == 0 && strlen(argv[a]) > 6)
dynStoreSz(e, arg, 4, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.w)
else if(strncmp(argv[a], "-", 1) == 0)
; // argument inconnu, ignorer
else
{
// premier argument ne commencant pas par "-" : nom du prog wp
for( ; a < argc; a++)
dynStoreSz(e, arg, 2, ++cpt, argv[a], DYN_LGNONE, cFM, cVM);
break;
}
}
if(dynExtractPos(e, arg, 3, DYN_NONE, cFM, DYN_NONE) <= 0)
{
dynStoreSz(e, arg, 3, DYN_NONE, getenv("WBIN"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
if(dynExtractPos(e, arg, 3, DYN_NONE, cFM, DYN_NONE) <= 0)
dynStoreSz(e, arg, 3, DYN_NONE, getenv("LD_LIBRARY_PATH"), DYN_LGNONE, cFM, DYN_NONE); // dernier recours...
}
//
if(dynExtractPos(e, arg, 5, DYN_NONE, cFM, DYN_NONE) <= 0)
dynStoreSz(e, arg, 5, DYN_NONE, getenv("WLIB"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
//
if(dynExtractPos(e, arg, 4, DYN_NONE, cFM, DYN_NONE) <= 0)
dynStoreSz(e, arg, 4, DYN_NONE, getenv("WSRC"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
/*
arg<1> = options en MV
arg<2> = prog et parametres en MV
arg<3> = WBIN (.o .so) => invoke, LD_LIBRARY_PATH
arg<4> = WSRC (.w) => lwc
arg<5> = WLIB (.wp .wa) => call, lwa lwc
arg<6> = les argv ligne de commande AVANT le prog wp
*/
}
+264 -203
View File
@@ -20,6 +20,9 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifdef WINLIB
#include "windows.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -28,8 +31,7 @@
#include "langage.h"
#include "dynamic.h"
#include "instr.h"
char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
#include "arg.c"
env e;
@@ -45,7 +47,8 @@ env e;
int subNiv;
Dynamic adrLabel;
/*
adrLabel<1> = label, adrLabel<2> = offset (adresse) du label
adrLabel<1> = label
adrLabel<2> = offset (adresse) du label
adrLabel<3, subNiv> = ad debut sub en cours (debut PROG/SUBR)
adrLabel<4> = liste labels dans des JUMP a completer
adrLabel<5> = liste de la position du JUMP ou ecrire l'offset (adresse) du label
@@ -80,14 +83,29 @@ void decodeString(env * e, Dynamic * this)
{
/* TODO ! voir avec le compilateur s'il ne fait pas deja le travail */
/* genw remplace " par #22 et ' ' par #20 : on fait l'inverse ici */
dynChange(e, this, "#22", "\"", DYN_ALL);
dynChange(e, this, "#20", " ", DYN_ALL);
/* + pbm #0A qui saute une ligen et ok ici ... */
//dynChange(e, this, "#22", "\"", DYN_ALL);
//dynChange(e, this, "#20", " ", DYN_ALL);
dynCleanHexaMark(e, this);
}
Dynamic pcode;
ent64s posOffset;
void PCODE(int x)
{
dynConcatSz(&e,&pcode,"0",1);
pcode.ptr[pcode.mLg-1]=((octet)x);
}
void PCODEP(int x)
{
pcode.ptr[posOffset++]=((octet)x);
}
int assembler(env * e, char * fichier, int * cptLig)
{
#define PCODE(x) {dynConcatSz(e,&pcode,"0",1);pcode.ptr[pcode.mLg-1]=((octet)x);}
#define PCODEP(x) pcode.ptr[pcode.mLg++]=((octet)x);
//#define PCODE(x) {dynConcatSz(e,&pcode,"0",1);pcode.ptr[pcode.mLg-1]=((octet)x);}
//#define PCODEP(x) pcode.ptr[pcode.mLg++]=((octet)x);
//
dynInit(e, &e->int_dynamic, DYN_LGMIN);
//
@@ -95,8 +113,8 @@ int assembler(env * e, char * fichier, int * cptLig)
if(dynRead(e, &e->int_dynamic, fichier) != OK)
return -1;
// traiter chaque ligne
Dynamic ligne, tmp, pcode, varsys, trav;
int ret = OK, i, sav, offset, instr, debutSub;
Dynamic ligne, tmp, varsys, trav;
int ret = OK, i, sav, offset, instr, debutSub; // precInstr = -1;
int premiere_instr = 1, derniere_instr = 0;
long pos; // pour locate
ent64s num;
@@ -152,13 +170,13 @@ int assembler(env * e, char * fichier, int * cptLig)
debutSub = debutSub + 2 + pcode.ptr[debutSub + 1];
offset = pcode.mLg + 1 - debutSub;
// maj offset
sav = pcode.mLg;
//sav = pcode.mLg;
dynField(e, &adrLabel, &trav, 5, iLabel, cFM, cVM, 1);
pcode.mLg = dynToNum(e, &trav, DYN_FALSE, 0);
PCODEP((offset >> 16) & 255)
PCODEP((offset >> 8 ) & 255)
PCODEP(offset & 255)
pcode.mLg = sav;
posOffset = dynToNum(e, &trav, DYN_FALSE, 0);
PCODEP((offset >> 16) & 255);
PCODEP((offset >> 8 ) & 255);
PCODEP(offset & 255);
//pcode.mLg = sav;
dynDel(e, &adrLabel, 4, iLabel, cFM, cVM, 1);
dynDel(e, &adrLabel, 5, iLabel, cFM, cVM, 1);
}
@@ -211,8 +229,8 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
num = dynToNum(e, &tmp, 0, 3) & 255;
if(tmp.mInternal == DYN_ERR) ret = -3; // erreur conversion
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
break;
case IN_JUMP:
case IN_JMPF:
@@ -223,27 +241,27 @@ int assembler(env * e, char * fichier, int * cptLig)
pos = dynLocateSz(e, &adrLabel, tmp.mPtr, cVM, 1, cFM);
if(pos > 0)
{
PCODE(instr)
PCODE(instr);
dynField(e, &adrLabel, &trav, 2, pos, cFM, cVM, 1); // adresse debut loop
offset = dynToNum(e, &trav, DYN_FALSE, 8);
dynField(e, &adrLabel, &trav, 3, subNiv, cFM, cVM, 1); // adresse debut sub en cours
debutSub = dynToNum(e, &trav, DYN_FALSE, 8);
if(subNiv > 1)
debutSub = debutSub + 2 + pcode.ptr[debutSub + 1];
debutSub = debutSub + 2 + 3 + 1 + pcode.ptr[debutSub + 1]; // se mettre APRES l'instruction SUBR/PHDS/PIDS (5 + lg et le 1 pour annuler le +1 qui est apres...)
offset = offset + 1 - debutSub; // ad debut loop - debut du prog/sub en cours
PCODEP((offset >> 16) & 255)
PCODEP((offset >> 8 ) & 255)
PCODEP(offset & 255)
PCODE((offset >> 16) & 255); // 23/11/2025 - verif PCODE ok a la place de PCODEP
PCODE((offset >> 8 ) & 255); // 23/11/2025 - verif PCODE ok a la place de PCODEP
PCODE(offset & 255); // 23/11/2025 - verif PCODE ok a la place de PCODEP
}
else
{
PCODE(instr)
PCODE(instr);
// memoriser l'endroit ou on veut mettre l'offset du jump a faire adrLabel<4> et <5>
dynIns(e, &adrLabel, 4, 1, &tmp, cFM, cVM);
dynInsSz(e, &adrLabel, 5, 1, Int32ToSz(pcode.mLg, DYN_FALSE, 0), DYN_LGNONE, cFM, cVM);
PCODE(0)
PCODE(0)
PCODE(0)
PCODE(0);
PCODE(0);
PCODE(0);
}
break;
case IN_DECL:
@@ -254,20 +272,20 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_SRCL:
// SRCL
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
num = dynToNum(e, &tmp, 0, 8) & 0xFFFFFF;
if(tmp.mInternal == DYN_ERR) ret = -3; // erreur conversion
PCODE(instr)
PCODE((num >> 16) & 255)
PCODE((num >> 8) & 255)
PCODE(num & 255)
PCODE(instr);
PCODE((num >> 16) & 255);
PCODE((num >> 8) & 255);
PCODE(num & 255);
break;
case IN_PHDS:
case IN_PIDS:
@@ -277,15 +295,15 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
if(num == 1 && tmp.mPtr[0] == '_') // assembler SUBR _ pour avoir lg = 0
if(num == 1 && tmp.mPtr[0] == '_') // assembler SUBR _ pour avoir lg = 0 (?? A GARDER ?? FDE 08/03/2026)
num = 0;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(0)
PCODE(0)
PCODE(0)
PCODE(tmp.mPtr[p]);
PCODE(0);
PCODE(0);
PCODE(0);
/* nouvelle methode */
dynStoreSz(e, &adrLabel, 3, ++subNiv, Int32ToSz(sav, DYN_FALSE, 0), DYN_LGNONE, cFM, cVM);
break;
@@ -294,28 +312,28 @@ int assembler(env * e, char * fichier, int * cptLig)
if(subNiv < 2) { ret = -8; break; } // erreur descente de niveau incorrecte
dynField(e, &adrLabel, &trav, 3, subNiv--, cFM, cVM, 1);
debutSub = dynToNum(e, &trav, DYN_FALSE, 8);
sav = pcode.mLg;
pcode.mLg = debutSub + 2 + pcode.ptr[debutSub + 1];
offset = sav + 1 - debutSub;
PCODEP((offset >> 16) & 255)
PCODEP((offset >> 8 ) & 255)
PCODEP(offset & 255)
pcode.mLg = sav;
PCODE(instr)
//sav = pcode.mLg;
posOffset = debutSub + 2 + pcode.ptr[debutSub + 1];
offset = pcode.mLg + 1 - debutSub;
PCODEP((offset >> 16) & 255);
PCODEP((offset >> 8 ) & 255);
PCODEP(offset & 255);
//pcode.mLg = sav;
PCODE(instr);
break;
case IN_BEXC:
// BEXC
// memoriser la position pour renseigner l'offset plus tard => idem adrLabel<3> : BEXC juste apres PROG et SUBR !
PCODE(instr)
PCODE(0)
PCODE(0)
PCODE(0)
PCODE(instr);
PCODE(0);
PCODE(0);
PCODE(0);
break;
case IN_EXCE:
// EXCE
// debut du bloc except : ecrire l'adresse dans l'instruction BEXC
PCODE(instr)
sav = pcode.mLg;
PCODE(instr);
//sav = pcode.mLg;
/* nouvelle methode */
dynField(e, &adrLabel, &trav, 3, subNiv, cFM, cVM, 1); // adresse debut sub en cours
debutSub = dynToNum(e, &trav, DYN_FALSE, 8);
@@ -323,31 +341,31 @@ int assembler(env * e, char * fichier, int * cptLig)
{
debutSub = debutSub + 2 + pcode.ptr[debutSub + 1] + 3;
offset = pcode.mLg - debutSub;
pcode.mLg = debutSub + 1;
posOffset = debutSub + 1;
}
else
{
offset = pcode.mLg - debutSub;
pcode.mLg = debutSub + 1;
posOffset = debutSub + 1;
}
PCODEP((offset >> 16) & 255)
PCODEP((offset >> 8 ) & 255)
PCODEP(offset & 255)
pcode.mLg = sav;
PCODEP((offset >> 16) & 255);
PCODEP((offset >> 8 ) & 255);
PCODEP(offset & 255);
//pcode.mLg = sav;
break;
case IN_CATC:
// CATC
PCODE(instr)
PCODE(instr);
break;
case IN_THRW:
// THRW
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
num = dynToNum(e, &tmp, 0, 8) & 0xFFFFFF;
if(tmp.mInternal == DYN_ERR) ret = -3; // erreur conversion
PCODE(instr)
PCODE((num >> 16) & 255)
PCODE((num >> 8) & 255)
PCODE(num & 255)
PCODE(instr);
PCODE((num >> 16) & 255);
PCODE((num >> 8) & 255);
PCODE(num & 255);
break;
case IN_PART:
// PART
@@ -356,39 +374,35 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
num = dynToNum(e, &tmp, 0, 3) & 255;
if(tmp.mInternal == DYN_ERR) ret = -3; // erreur conversion
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
break;
case IN_RETN:
case IN_RETT:
// RETN / RETT
PCODE(instr)
break;
case IN_CRAZ:
// CRAZ
PCODE(instr)
// RETN / RETT / CRAZ
PCODE(instr);
break;
case IN_CLIB:
case IN_CALL:
// CLIB / CALL
PCODE(instr)
do
PCODE(instr);
//dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
//num = dynToNum(e, &tmp, 0, 3) & 255;
//if(tmp.mInternal == DYN_ERR) { ret = -3; break; } // erreur conversion
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
if(num == 1 && tmp.mPtr[0] == '_')
{
//dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
//num = dynToNum(e, &tmp, 0, 3) & 255;
//if(tmp.mInternal == DYN_ERR) { ret = -3; break; } // erreur conversion
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
if(num == 1 && tmp.mPtr[0] == '_')
{
PCODE(0)
break;
}
PCODE(num)
PCODE(0);
}
else
{
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
} while(TRUE);
PCODE(tmp.mPtr[p]);
}
break;
case IN_PVAT:
case IN_TYPO:
@@ -397,7 +411,7 @@ int assembler(env * e, char * fichier, int * cptLig)
case IN_RNXT:
case IN_CPHA:
// PVAT / TYPO / PSHT / SELE / RNXT / CPHA
PCODE(instr)
PCODE(instr);
break;
case IN_CPSH:
case IN_PARM:
@@ -410,8 +424,13 @@ int assembler(env * e, char * fichier, int * cptLig)
case IN_PIDH:
case IN_PHDO:
case IN_PIDO:
case IN_DELE:
case IN_PHDN:
case IN_PIDN:
case IN_PHDV:
case IN_PIDV:
case IN_NLET:
case IN_PVHD:
case IN_PVID:
// CPSH / PARM / PVAR / PVAH / PVAI / DELE / NLET / PHDE / PIDE
//dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
//num = dynToNum(e, &tmp, 0, 3) & 255;
@@ -419,33 +438,35 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_COMP:
// COMP
PCODE(instr)
PCODE(instr);
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(strcmp(tmp.mPtr, "EQ") == 0)
PCODE(CMP_EQ)
PCODE(CMP_EQ);
else if(strcmp(tmp.mPtr, "NE") == 0)
PCODE(CMP_NE)
PCODE(CMP_NE);
else if(strcmp(tmp.mPtr, "LT") == 0)
PCODE(CMP_LT)
PCODE(CMP_LT);
else if(strcmp(tmp.mPtr, "GT") == 0)
PCODE(CMP_GT)
PCODE(CMP_GT);
else if(strcmp(tmp.mPtr, "LE") == 0)
PCODE(CMP_LE)
PCODE(CMP_LE);
else if(strcmp(tmp.mPtr, "GE") == 0)
PCODE(CMP_GE)
PCODE(CMP_GE);
else if(strcmp(tmp.mPtr, "AND") == 0)
PCODE(CMP_AND)
PCODE(CMP_AND);
else if(strcmp(tmp.mPtr, "OR") == 0)
PCODE(CMP_OR)
PCODE(CMP_OR);
else if(strcmp(tmp.mPtr, "NOT") == 0)
PCODE(CMP_NOT)
PCODE(CMP_NOT);
else if(strcmp(tmp.mPtr, "FOR") == 0)
PCODE(CMP_FOR);
else
ret = -9; // code comparaison inconnu
break;
@@ -511,6 +532,10 @@ int assembler(env * e, char * fichier, int * cptLig)
// SRCH
case IN_SCHS:
// SCHS
case IN_SSRC:
// SSRC
case IN_SSCS:
// SSCS
case IN_CHNG:
// CHNG
case IN_INSE:
@@ -531,32 +556,36 @@ int assembler(env * e, char * fichier, int * cptLig)
// DESV
case IN_DEZV:
// DEZV
PCODE(instr)
case IN_SADV:
case IN_VLET:
case IN_HCOU:
case IN_DELE:
PCODE(instr);
break;
case IN_MODL:
// MODL
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 3 || tmp.mLg > 45) { ret = -4; break; } // erreur longueur nom module
num = tmp.mLg;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_PSHC:
// PSHC
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
num = dynToNum(e, &tmp, 1, 19);
if(tmp.mInternal == DYN_ERR) ret = -3; // erreur conversion
PCODE(instr)
PCODE((num >> 56) & 255)
PCODE((num >> 48) & 255)
PCODE((num >> 40) & 255)
PCODE((num >> 32) & 255)
PCODE((num >> 24) & 255)
PCODE((num >> 16) & 255)
PCODE((num >> 8) & 255)
PCODE(num & 255)
PCODE(instr);
PCODE((num >> 56) & 255);
PCODE((num >> 48) & 255);
PCODE((num >> 40) & 255);
PCODE((num >> 32) & 255);
PCODE((num >> 24) & 255);
PCODE((num >> 16) & 255);
PCODE((num >> 8) & 255);
PCODE(num & 255);
break;
case IN_PSH0:
case IN_PSH1:
@@ -579,7 +608,7 @@ int assembler(env * e, char * fichier, int * cptLig)
// WRIT
case IN_WRLN:
// WRLN
PCODE(instr)
PCODE(instr);
break;
case IN_PSHA:
// PSHA d1 : transco chaine / numero
@@ -589,19 +618,19 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &varsys, &tmp, 2, pos, ';', ',', 1);
num = dynToNum(e, &tmp, 0, 3) & 255;
if(tmp.mInternal == DYN_ERR) ret = -3; // erreur conversion
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
break;
case IN_DSET:
// DSET - TODO decoder la chaine, cas des \xx en hexa (recalcul lg : fn qui met a jour directement tmp et maj lg)
// DSET - TODO decoder la chaine, cas des #xx en hexa (recalcul lg : fn qui met a jour directement tmp et maj lg)
dynField(e, &ligne, &tmp, 2, 0, '"', 0, 1);
decodeString(e, &tmp);
if(tmp.mLg < 0 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom
num = tmp.mLg;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_DEXH:
// DEXH
@@ -617,102 +646,112 @@ int assembler(env * e, char * fichier, int * cptLig)
// DEZI
case IN_DSTO:
// DSTO
case IN_VLET:
// VLET
case IN_LETV:
// LETV
case IN_DCAT:
// DCAT
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom var
num = tmp.mLg;
if(num == 1 && tmp.mPtr[0] == '_') // assembler DEXF/DEXV/VLET/DCAT _ pour avoir lg = 0
if(num == 1 && tmp.mPtr[0] == '_') // assembler DEXF/DEXV/LETV/DCAT _ pour avoir lg = 0
num = 0;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_CLAS:
// CLAS
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom var
num = tmp.mLg;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom var
num = tmp.mLg;
if(num == 1 && tmp.mPtr[0] == '_') // assembler CLAS lg1 nom1 _ pour avoir lg2 = 0
num = 0;
PCODE(num)
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_DCMP:
// DCMP
//dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
PCODE(instr)
PCODE(instr);
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(strcmp(tmp.mPtr, "EQ") == 0)
PCODE(CMP_EQ)
PCODE(CMP_EQ);
else if(strcmp(tmp.mPtr, "NE") == 0)
PCODE(CMP_NE)
PCODE(CMP_NE);
else if(strcmp(tmp.mPtr, "LT") == 0)
PCODE(CMP_LT)
PCODE(CMP_LT);
else if(strcmp(tmp.mPtr, "GT") == 0)
PCODE(CMP_GT)
PCODE(CMP_GT);
else if(strcmp(tmp.mPtr, "LE") == 0)
PCODE(CMP_LE)
PCODE(CMP_LE);
else if(strcmp(tmp.mPtr, "GE") == 0)
PCODE(CMP_GE)
PCODE(CMP_GE);
else
ret = -9; // code comparaison inconnu
//
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom var
num = tmp.mLg;
PCODE(num)
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_INCL:
// INCL (lg=0 possible si rien)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 0 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_PNAM:
// PNAM (lg=0 possible si rien)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 0 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom ident
num = tmp.mLg;
PCODE(instr)
PCODE(num)
PCODE(instr);
PCODE(num);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p])
PCODE(tmp.mPtr[p]);
break;
case IN_PROG:
case IN_BACK:
case IN_LIBR:
// debut de programme executable directement (normal et demon) et debut library, non executable directement
PCODE(instr)
PCODE(instr);
/* nouvelle methode */
dynStoreSz(e, &adrLabel, 3, ++subNiv, Int32ToSz(pcode.mLg, DYN_FALSE, 0), DYN_LGNONE, cFM, cVM);
break;
case IN_SDBG:
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
num = tmp.mLg;
PCODE(instr);
PCODE((num >> 16) & 255);
PCODE((num >> 8) & 255);
PCODE(num & 255);
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p]);
break;
case IN_TEST:
// TEST
PCODE(instr)
PCODE(instr);
break;
case IN_ENDL:
case IN_ENDP:
// ENDL / ENDP : fin de librairie / prog directement executable
if(subNiv != 1) { ret = -8; break; } // erreur descente de niveau incorrecte
PCODE(instr)
PCODE(instr);
derniere_instr = 1;
break;
default:
@@ -734,27 +773,12 @@ int assembler(env * e, char * fichier, int * cptLig)
if(tmp.mLg != 0 && tmp.mPtr[0] != ';') { ret = -6; printf("tmp *%s*\n", tmp.mPtr);} // erreur en fin d'instruction
}
}
//precInstr = instr;
}
//
if(!ret)
{
// si pas d'erreur : copier dans le repertoire WBIN en renommant "xxx.wa" en "xxx.wp"
//char * wbin = getenv("WBIN");
//if(wbin == NULL)
// wbin = getenv("LD_LIBRARY_PATH");
//if(wbin == NULL)
//{
// ret = -11;
//}
//else
//{
// dynLet(e, &tmp, wbin, DYN_LGNONE);
// dynConcatSz(e, &tmp, e->path_sep, DYN_LGNONE);
// dynConcatSz(e, &tmp, fichier, DYN_LGNONE);
// tmp.mPtr[tmp.mLg - 1] = 'p';
// dynWrite(e, &pcode, tmp.mPtr);
//}
// ecrire au meme endroit que le .w et .wa
// si pas d'erreur, ecrire au meme endroit que le .wa (=> dans WLIB)
dynLet(e, &tmp, fichier, DYN_LGNONE);
tmp.mPtr[tmp.mLg - 1] = 'p';
dynWrite(e, &pcode, tmp.mPtr);
@@ -904,15 +928,10 @@ int disassembler(env * e, char * fichier)
case IN_CALL:
// CLIB / CALL
si++;
do
{
lg = pcode.ptr[si++];
if(lg == 0)
break;
lg = pcode.ptr[si++];
if(lg > 0)
for(int p = 0; p < lg; p++)
printf("%c", pcode.mPtr[si++]);
printf(" ");
} while(TRUE);
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
@@ -935,8 +954,13 @@ int disassembler(env * e, char * fichier)
case IN_PIDH:
case IN_PHDO:
case IN_PIDO:
case IN_DELE:
case IN_PHDN:
case IN_PIDN:
case IN_PHDV:
case IN_PIDV:
case IN_NLET:
case IN_PVHD:
case IN_PVID:
case IN_PNAM:
case IN_INCL:
// CPSH / PARM / PVAR / PVAH / PVAI / DELE / NLET / PNAM / INCL / PHDE / PIDE
@@ -966,7 +990,7 @@ int disassembler(env * e, char * fichier)
// COMP
si++;
num = pcode.ptr[si++];
if(num < CMP_EQ || num > CMP_NOT)
if(num < CMP_EQ || num > CMP_FOR)
printf("%d\n", num);
else
{
@@ -1037,6 +1061,10 @@ int disassembler(env * e, char * fichier)
// SRCH
case IN_SCHS:
// SCHS
case IN_SSRC:
// SSRC
case IN_SSCS:
// SSCS
case IN_CHNG:
// CHNG
case IN_INSE:
@@ -1057,6 +1085,10 @@ int disassembler(env * e, char * fichier)
// DESV
case IN_DEZV:
// DEZV
case IN_SADV:
case IN_VLET:
case IN_HCOU:
case IN_DELE:
si++;
printf("\n");
dumpHex(&pcode, si_instr, si);
@@ -1161,8 +1193,8 @@ int disassembler(env * e, char * fichier)
// DEZI
case IN_DSTO:
// DSTO
case IN_VLET:
// VLET
case IN_LETV:
// LETV
case IN_DCAT:
// DCAT
si++;
@@ -1209,6 +1241,16 @@ int disassembler(env * e, char * fichier)
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_SDBG:
si++;
lg = pcode.ptr[si++];
lg = lg * 256 + pcode.ptr[si++];
lg = lg * 256 + pcode.ptr[si++];
for(int p = 0; p < lg; p++)
printf("%c", pcode.mPtr[si++]);
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_TEST:
// TEST
si++;
@@ -1240,13 +1282,14 @@ int disassembler(env * e, char * fichier)
dynFree(e, &tmp);
dynFree(e, &varsys);
dynFree(e, &niv);
return 0;
return OK;
}
/* ***************************************************************************************************** */
int main(int argc, char * argv[])
{
int cr = 0;
int cr = OK;
Dynamic arg, wlib, fichier;
/* */
/* avis de licence */
printf("W language Copyright 2024,2025 lanisys.fr\n");
@@ -1254,7 +1297,7 @@ int main(int argc, char * argv[])
/* argument : fichier a assembler/desassembler (si -d) */
if(argc < 2)
{
printf("Usage: lwa [-d] <fichier>\n");
printf("Usage: lwa [-d] [-WLIB:<chemin>] <fichier.wa|fichier.wp>\n");
exit(-1);
}
/* */
@@ -1264,40 +1307,58 @@ int main(int argc, char * argv[])
lap = ts.tv_sec * 1000000 + (ts.tv_nsec / 1000);
/* */
init_env(&e);
dynInit(&e, &arg, 0);
dynInit(&e, &wlib, 0);
dynInit(&e, &fichier, 0);
/* */
if(strcmp(argv[1], "-d") == 0)
GetArgs(&e, argc, argv, &arg);
dynExtractField(&e, &arg, 5, &wlib);
dynExtractSubField(&e, &arg, 2, 1, &fichier); // fichier = .wa a assembler / .wp a desassembler
/* */
if(fichier.mLg < 4)
{
if(argc >= 3)
{
#ifndef UNIX
cr = disassembler(&e, argv[2]);
#else
cr = disassembler(&e, argv[2]);
#endif
}
else
printf("Usage: lwa -d <fichier>\n");
printf("Nom de fichier incorrect\n");
cr = -14;
}
else if(wlib.mLg == 0)
{
printf("Variable d'environnement WLIB non definie\n");
cr = -15;
}
else
{
int numLig = 0;
#ifndef UNIX
if((cr = assembler(&e, argv[1], &numLig)) != OK)
#else
if((cr = assembler(&e, argv[1], &numLig)) != OK)
#endif
if(wlib.mPtr[wlib.mLg - 1] != e.path_sep[0])
dynConcatSz(&e, &wlib, e.path_sep, 1);
dynConcat(&e, &wlib, &fichier);
if(dynLocateSz(&e, &arg, ARG_DISASM, cVM, 1, cFM) > 0)
{
printf("Erreur %d a la ligne %d\n", cr, numLig);
#ifndef UNIX
cr = disassembler(&e, wlib.mPtr);
#else
cr = disassembler(&e, wlib.mPtr);
#endif
}
else
{
printf("Result : OK, lines=%d\n", numLig);
int numLig = 0;
#ifndef UNIX
if((cr = assembler(&e, wlib.mPtr, &numLig)) != OK)
#else
if((cr = assembler(&e, wlib.mPtr, &numLig)) != OK)
#endif
{
printf("Erreur %d a la ligne %d\n", cr, numLig);
}
else
{
printf("Result : OK, lines=%d\n", numLig);
}
}
}
/* */
if(clock_gettime_monotonic(&ts) != -1)
lap = ts.tv_sec * 1000000 + (ts.tv_nsec / 1000) - lap;
printf("exit:%u ", cr);
printf("exit:%d ", cr);
if(lap < 1500)
printf("(%llu µs)\n", lap);
else if(lap < 1500000)
+231
View File
@@ -0,0 +1,231 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "langage.h"
#include "var.h"
#include "buffer.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/*
Dans le contexte des IPC, memoire partagee, contenant un buffer (donc partagé), le champ "ptr" pointe forcement a la suite de l'entete,
car un malloc ne fonctionne pas en inter process.
Contrairement à la création avec "var_init", destiné a ne pas etre partage, ptr est créé par un malloc
La macro BUFPTR permet de gerer ces 2 cas : si le buffer est en memoire partagee, le champ ptr = NULL et il suffit alors d'aller juste apres l'entete
pour trouver les donnees. Si le buffer est cree avec var_init, il faut utiliser la valeur de ptr directement.
*/
/*
lgmax = taille buffer
max lg message = lgmax - 4 => un message = lg (2 octets) + msg
cas 0 read = write : buffer vide : lg msg max = lgmax - 4 (et maxi 65535)
cas 1 : read <= write (inclus cas 0)
+-------------^*********************^------------------+ lgmax
read write
occ = write - read ; free = lgmax - (write - read) - 4
cas 2 : read > write
+********^---------------------------------------^*****+ lgmax
write read
occ = write + (lgmax - read) ; free = read - write - 4
*/
//#define BUFPTR(x) (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr)
pointeur BUFPTR(var * x)
{
return (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr);
}
WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
{
ent16 lg, lgfin; /* taille max d'un element dans un buffer : 64 Ko */
ent64 p;
if(varbuf == NULL || v == NULL)
return;
if(varbuf->type != VAR_BUFFER)
return;
/* uniquement lecture dans VAR_DYNAMIC : raz var sinon */
if(v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
if(v->type != VAR_DYNAMIC)
{
var_free(e, v, TRUE);
var_init(e, v, VAR_DYNAMIC, 0, 0, NULL);
if(v->type == VAR_NULL)
{
/* erreur alloc memoire */
e->exception = EX_MEM;
return;
}
}
dynLet(e, v, NULL, DYN_LGNONE);
if(varbuf->read == varbuf->write)
return; /* buffer vide : var dynamic vide aussi */
/* */
p = varbuf->read;
lg = *(octet *)(BUFPTR(varbuf) + p++) * 256;
if(p >= varbuf->lgmax) p = 0;
lg += *(octet *)(BUFPTR(varbuf) + p++);
if(p >= varbuf->lgmax) p = 0;
if(lg > 0)
{
if(dynCtrl(e, v, lg, TRUE) != DYN_OK) /* avec RAZ */
return;
/* */
if(lg <= (lgfin = varbuf->lgmax - p))
{
/* copier un seul bloc */
memcopie(v->ptr, BUFPTR(varbuf) + p, lg);
//memcpy(v->ptr, varbuf->ptr + p, lg);
v->lg = lg;
*(v->ptr + lg) = 0; /* \0 de fin de chaine */
if(p + lg >= varbuf->lgmax)
varbuf->read = 0; /* cela ne peut pas etre plus loin, car sinon il y aurait eu 2 blocs a lire */
else
varbuf->read = p + lg;
}
else
{
/* 2 blocs */
memcopie(v->ptr, BUFPTR(varbuf) + p, lgfin);
//memcpy(v->ptr, varbuf->ptr + p, lgfin);
memcopie(v->ptr + lgfin, BUFPTR(varbuf), lg - lgfin);
//memcpy(v->ptr + lgfin, varbuf->ptr, lg - lgfin);
varbuf->read = lg - lgfin;
}
}
else
varbuf->read = p;
}
WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
{
ent64 p, lgfin;
if(varbuf == NULL || v == NULL)
return;
if(v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
if(varbuf->type != VAR_BUFFER || v->type != VAR_DYNAMIC)
return;
/* uniquement ecriture d'une VAR_DYNAMIC */
if(v->lg > (varbuf->lgmax / 2)) // pour pouvoir ecrire au moins 2 items dans le buffer
{
e->exception = EX_BUFOVF; /* trop grand a ecrire */
return;
}
ent64 vbread = varbuf->read;
if(varbuf->write < vbread)
{
/* ecriture en une fois, + 3 car lg sur 16 bits en plus et laisser au moins 1 octet libre => read=write veut dire vide ! */
if(vbread - varbuf->write < v->lg + 3)
{
e->exception = EX_BUFOVF; /* pas assez de place */
return;
}
/* */
p = varbuf->write;
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
p++;
*(BUFPTR(varbuf) + p) = v->lg & 255;
p++;
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
varbuf->write = p + v->lg;
}
else
{
/* ecriture en une ou 2 fois */
if(varbuf->lgmax + vbread - varbuf->write < v->lg + 3) /* lgbuffer - (write - read) */
{
e->exception = EX_BUFOVF; /* pas assez de place */
return;
}
p = varbuf->write;
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
p++;
if(p >= varbuf->lgmax) p = 0;
*(BUFPTR(varbuf) + p) = v->lg & 255;
p++;
if(p >= varbuf->lgmax) p = 0;
if(v->lg == 0)
{
varbuf->write = p;
return;
}
if(v->lg <= (lgfin = varbuf->lgmax - p))
{
/* copier en une fois */
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
if(p + v->lg >= varbuf->lgmax)
varbuf->write = 0; /* pas plus cas sinon il y aurait eu copie en 2 fois */
else
varbuf->write = p + v->lg;
}
else
{
/* en 2 fois */
memcopie(BUFPTR(varbuf) + p, v->ptr, lgfin);
//memcpy(varbuf->ptr + p, v->ptr, lgfin);
memcopie(BUFPTR(varbuf), v->ptr + lgfin, v->lg - lgfin);
//memcpy(varbuf->ptr, v->ptr + lgfin, v->lg - lgfin);
varbuf->write = v->lg - lgfin;
}
}
}
WAPIDECL void buffer_clear(env * e, var * varbuf)
{
if(varbuf == NULL)
return;
if(varbuf->type != VAR_BUFFER)
return;
varbuf->read = 0;
varbuf->write = 0;
memset(BUFPTR(varbuf), 0, varbuf->lgmax);
}
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg)
{
if(varbuf == NULL)
return;
if(varbuf->type != VAR_BUFFER)
return;
printf("buffer lgmax=%lld read=%lld write=%lld\n", varbuf->lgmax, varbuf->read, varbuf->write);
if(lg == 0)
lg = varbuf->lgmax;
/* affichage brut en hexa */
hex2((char *)BUFPTR(varbuf), lg, 32);
}
+35
View File
@@ -0,0 +1,35 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifndef BUFFER_H
#define BUFFER_H
#include "apidecl.h"
WAPIDECL void buffer_read(env * e, var * varbuf, var * v);
WAPIDECL void buffer_write(env * e, var * varbuf, var * v);
WAPIDECL void buffer_clear(env * e, var * varbuf);
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg);
/* ********************************************** */
#endif
+38 -17
View File
@@ -1,30 +1,50 @@
BUILD=`date +%Y%m%d%H%M%S`
echo BUILD $BUILD
echo 0. Compilation pour shared lib
gcc -c w_src/dynamic.c -s -Wall -DUNIX -m64 -fPIC -o exec/dynamic.o
gcc -c w_src/dynamic.c -s -Wall -DUNIX -m64 -fPIC -o exec/dynamic.o -Wno-unused-value
gcc -c w_src/var.c -s -Wall -DUNIX -m64 -fPIC -o exec/var.o
gcc -c w_src/hashtable.c -s -Wall -DUNIX -m64 -fPIC -o exec/hashtable.o
gcc -c w_src/buffer.c -s -Wall -DUNIX -m64 -fPIC -o exec/buffer.o
gcc -c w_src/global.c -s -Wall -DUNIX -m64 -fPIC -o exec/global.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o -o exec/libw.so
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o
gcc -c w_src/rep.c -s -Wall -DUNIX -m64 -fPIC -o exec/rep.o
gcc -c w_src/lex.c -s -Wall -DUNIX -m64 -fPIC -o exec/lex.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o exec/lex.o -o exec/libw.so
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o exec/lex.o
echo 1. Compilation de modeleMod.c
gcc -shared -s -o exec/modele.o w_src/modeleMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 1. Compilation de templateMod.c
gcc -shared -s -o exec/template.o w_src/templateMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 2. Compilation de fileMod.c
gcc -shared -s -o exec/file.o w_src/fileMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 3. Compilation de sockMod.c
gcc -shared -s -o exec/sock.o w_src/sockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/sock_lib.so w_src/sock_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/sock.o w_src/sockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:sock_lib.so
echo 4. Compilation de dbMod.c et dbpgsql.c
gcc -shared -s -o exec/db.o w_src/dbMod.c -m64 -DUNIX -Wall -ldl -fPIC -L./exec -l:libw.so
#echo 4. Compilation de dbMod.c et dbpgsql.c
#gcc -shared -s -o exec/db.o w_src/dbMod.c -m64 -DUNIX -Wall -ldl -fPIC -L./exec -l:libw.so
#gcc -shared -s -o exec/pgsql.o w_src/dbpgsql.c -m64 -DUNIX -Wall -I/usr/include/postgresql -fPIC -L./exec -l:libw.so
echo 4. Compilation de encodMod.c
gcc -shared -s -o exec/encod_lib.so w_src/encod_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -Wno-char-subscripts
#gcc -shared -s -o exec/encod.o w_src/encodMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:encod_lib.so
echo 5. Compilation de lzwMod.c
gcc -shared -s -o exec/lzw.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/lzw_lib.so w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/lzw.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:lzw_lib.so
echo 5. Compilation de pdfMod.c
gcc -shared -s -o exec/pdf_lib.so w_src/pdf_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/pdf.o w_src/pdfMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:pdf_lib.so -l:lzw_lib.so
echo 6. Compilation de jsonMod.c
gcc -shared -s -o exec/json_lib.o w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.o
gcc -shared -s -o exec/json_lib.so w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.so
echo 6. Compilation de shmMod.c
gcc -shared -s -o exec/shm_lib.so w_src/shm_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/shm.o w_src/shmMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:shm_lib.so
echo 7. Compilation de timeMod.c
gcc -shared -s -o exec/time.o w_src/timeMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
@@ -39,7 +59,7 @@ echo 10. Compilation de randomMod.c
gcc -shared -s -o exec/random.o w_src/randomMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 11. Compilation et link de langage.c
gcc w_src/langage.c -s -o exec/lw -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so
gcc w_src/langage.c -s -o exec/lw -ldl -m64 -DUNIX -DBUILD=$BUILD -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:shm_lib.so
echo 12. Compilation et link de assembler.c
gcc w_src/assembler.c -s -o exec/lwa -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so
@@ -48,11 +68,12 @@ echo 13. Generation du formatteur de code
gcc w_src/format.c -s -o exec/lwf -Wall -m64 -DUNIX -L./exec -l:libw.so
echo 14. Generation du generateur de fichier lex
gcc w_src/genlex.c -o exec/genlex -s -Wall -m64 -DUNIX -L./exec -l:libw.so
gcc w_src/genlex.c -o exec/wlex -s -Wall -m64 -DUNIX -L./exec -l:libw.so
echo 15. Generation de l\'analyseur de source w
gcc w_src/genw.c -s -o exec/genw -Wall -m64 -DUNIX -Wno-stringop-truncation -L./exec -l:libw.so
echo 15. Generation de l\'analyseur de source w \(compilateur w\)
gcc w_src/genw.c -s -o exec/lwc -Wall -m64 -DUNIX -Wno-stringop-truncation -L./exec -l:libw.so
echo "compress => gcc compress.c -s -o compress -Wall -m64 -DUNIX -L./exec -l:libw.so"
echo "test_utf => gcc test_utf.c -s -o utf -Wall -m64 -DUNIX -L./exec -l:libw.so"
echo "test_pdf => gcc test_pdf.c -s -o pdf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:pdf_lib.so -l:lzw_lib.so"
echo "rep => gcc rep.c -s -o rep -Wall -m64 -DUNIX -L./exec -l:libw.so"
echo "package => dpkg-deb --build wlanguage"
+82
View File
@@ -0,0 +1,82 @@
@echo off
cd "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build"
call vcvars64.bat
cd "C:\Users\Poupougne42\source\repos\win_w_src"
echo ------------------------------------------------------------------------------------------
echo 0. Compilation pour dynamic lib DLL
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\libw.dll w_src\dynamic.c w_src\var.c w_src\hashtable.c w_src\buffer.c w_src\global.c w_src\rep.c w_src\lex.c /DEBUG:NONE
echo 1a. Compilation de templateMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\template.dll w_src\templateMod.c exec\libw.lib /DEBUG:NONE
echo 1b. Compilation de fileMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\file.dll w_src\fileMod.c exec\libw.lib /DEBUG:NONE
echo 1c. Compilation de timeMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\time.dll w_src\timeMod.c exec\libw.lib /DEBUG:NONE
echo 1d. Compilation de hashMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\hash.dll w_src\hashMod.c exec\libw.lib /DEBUG:NONE
echo 1e. Compilation de systemMod.c (ws2_32.lib pour socket)
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\system.dll w_src\systemMod.c exec\libw.lib ws2_32.lib advapi32.lib /DEBUG:NONE
echo 1f. Compilation de randomMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\random.dll w_src\randomMod.c exec\libw.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 2a. Compilation de jsonMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\json_lib.dll w_src\json_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /DEBUG:NONE
echo 2b. Compilation de shmMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\shm_lib.dll w_src\shm_lib.c exec\libw.lib advapi32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\shm.dll w_src\shmMod.c exec\libw.lib exec\shm_lib.lib /DEBUG:NONE
echo 2c. Compilation de lzwMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\lzw_lib.dll w_src\lzw_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lzw.dll w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
echo 2d. Compilation de pdfMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\pdf_lib.dll w_src\pdf_lib.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\pdf.dll w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib /DEBUG:NONE
echo 2e. Compilation de sockMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sock_lib.dll w_src\sock_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\sock.dll w_src\sockMod.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE
echo 2f. Compilation de encodMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\encod_lib.dll w_src\encod_lib.c exec\libw.lib /DEBUG:NONE
rem cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 3a. Generation lw.exe
cl w_src\langage.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lw.exe exec\libw.lib exec\shm_lib.lib advapi32.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3b. Generation lwa.exe
cl w_src\assembler.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwa.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3c. Generation lwc.exe
cl w_src\genw.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwc.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3d. Generation lwf.exe
cl w_src\format.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwf.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3d. Generation wlex.exe
cl w_src\genlex.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\wlex.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
rem echo 3e. Generation test.exe
rem cl w_src\test.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\test.exe exec\libw.lib exec\encod_lib.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo ------------------------------------------------------------------------------------------
echo 4. Purge
del .\*.obj
del exec\*.obj
del exec\*.lib
del exec\*.exp
dir exec
exit
+8 -8
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -86,7 +86,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -102,14 +102,14 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat->fnDb = NULL;
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
//*** code specifique ici
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
@@ -119,7 +119,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -133,7 +133,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "conn", 4) == 0)
else if(modFnIs(e, "conn", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -182,7 +182,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "disc", 4) == 0)
else if(modFnIs(e, "disc", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -208,7 +208,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "info", 4) == 0)
else if(modFnIs(e, "info", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
+9 -9
View File
@@ -221,7 +221,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
// -----------------------------------------------------------
if(strncmp(e->fn, "read", 4) == 0)
if(modFnIs(e, "read", 4))
{
// param<1> = no fichier ; param<2> = cle
dynRemove(e, param, &p_etat->mTmp, cFM, DYN_TRUE);
@@ -319,11 +319,11 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
return EX_DB_ELSE; // pas d'erreur : mettre le code pour "non trouve" ELSE
}
}
else if(strncmp(e->fn, "write", 4) == 0)
else if(modFnIs(e, "write", 5))
{
//
}
else if(strncmp(e->fn, "open", 4) == 0)
else if(modFnIs(e, "open", 4))
{
// param<1> = nom table ; si ok renvoie en retour param<1> = id fichier (indice du tableau)
int lgSav = p_etat->mBase.mLg;
@@ -376,7 +376,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
dynSetLen(e, &p_etat->mBase, lgSav);
}
else if(strncmp(e->fn, "create", 5) == 0)
else if(modFnIs(e, "create", 5))
{
// cree la table : param<1> nom ; modulo param<2> ; separateur param<3>
fileHeader info;
@@ -421,7 +421,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
}
else if(strncmp(e->fn, "close", 5) == 0)
else if(modFnIs(e, "close", 5))
{
// param<1> = no fichier
int pos = dynToNum(e, param, 0, 6);
@@ -437,7 +437,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
// sinon, fichier deja ferme : RAS
}
}
else if(strncmp(e->fn, "setup", 5) == 0)
else if(modFnIs(e, "setup", 5))
{
// sortir si mId deja present (!=0) : une base est deja ouverte
// param<1> = repertoire de base => sa cle d'acces = mKey
@@ -488,7 +488,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
}
else if(strncmp(e->fn, "init", 4) == 0)
else if(modFnIs(e, "init", 4))
{
// si init deja fait, ras
if(p_etat == NULL)
@@ -502,7 +502,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
dynInit(e, &p_etat->mEntry, DYN_LGMIN);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
struct shmid_ds attrs = {0};
// liberation specifique au module avant arret process
@@ -534,7 +534,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
memfree(e, p_etat);
*etat = NULL;
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
dynLet(e, param, "100", 3); // version 1.00 ici
+619 -209
View File
File diff suppressed because it is too large. Load diff
+11
View File
@@ -0,0 +1,11 @@
; liste des commandes et mots cles en mode debug
blanc: (1,*,#20#09#0A#0D)
commande: (1,2,a-zA-Z)
aide: (1,1,?)
nombre: (1,9,0-9)
ajouter: (1,1,#2B) ; +
supprimer:(1,1,#2D) ; -
ident: (1,1,#3A) (1,1,a-zA-Z_) (0,23,a-zA-Z0-9) ; :_abcABC123
identnext:(1,1,#2E) (1,1,a-zA-Z) (0,23,a-zA-Z0-9) ; .abcABC123
reste: (1,1,#00-#FF)
+99
View File
@@ -0,0 +1,99 @@
;
; for background w process debugging
; using shm_lib on buffer "dbg<pid>" for the debugged process
; Usage: lw debug <pid2debug>
;
begin wdebug
declare idProc, msg, pid, cmd, ret, capt, again, delay, debugging, signal
declare OK, ERROR
let debugging = @false
let OK = 0
let ERROR = neg(1)
;
sub WriteProcess(id, message, cr)
invoke shm&set(id, message)
let cr = OK
except
let cr = ERROR
catch
endsub
;
sub ReadProcess(message, cr)
invoke shm&get(message)
let cr = OK
except
let cr = ERROR
catch
endsub
; ********************************************************
;
let pid = field(@arg, @currfm, 2)
if pid = '' or type(pid) # @varnumber then
let msg = 'Incorrect pid number (':pid:'), abort'
echonl msg
return
endif
;
let idProc = 'dbg':pid
let msg = 'Start debugging process ':pid
echonl msg
;
loop
let msg = 'Sending SIGUSR1 signal and wait 1 second'
echonl msg
let capt = ''
let ret = 0
let signal = 10
invoke system&sendSignal(pid, signal)
; now waiting for shm to init from signaled process
let delay = 1
invoke system&sleep(delay)
;
let msg = '%':@prog
do WriteProcess(idProc, msg, ret)
breakon ret = OK
; retry ?
let msg = 'Process ':pid:" don't respond to debug start message (":msg:"), try again (Y/N) ? "
echo msg
input again
breakon again # 'y' and again # 'Y'
endloop
returnon ret # OK
;
; ok, we can debug background process now
; 1. read prompt
; 2. get command from user
; 3. send command
; 4. repeat from step 1
let msg = "Ready for debuging... ('q' to end session)"
echonl msg
let delay = 0.1
let debugging = @true
loop
do ReadProcess(msg, ret)
breakon ret # OK or msg = '%'
if msg # '' then
echo msg
loop
let cmd = ''
input cmd
breakon cmd # ''
endloop
;
do WriteProcess(idProc, cmd, ret)
breakon ret # OK
else
invoke system&sleep(delay)
endif
endloop
let msg = "End of debugging"
echonl msg
;
except
if debugging then
let cmd = '%'
do WriteProcess(idProc, cmd, ret)
endif
let msg = 'Exception ':@except
echonl msg
end
+9
View File
@@ -0,0 +1,9 @@
blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,reste,8
1,-1,20:09:0A:0D
1,2,61-7A:41-5A
1,1,3F
1,9,30-39
1,1,2B
1,1,2D
1,1,3A;1,1,5F:61-7A:41-5A;0,23,61-7A:41-5A:30-39
1,1,00-FF
+1079 -532
View File
File diff suppressed because it is too large. Load diff
+100 -75
View File
@@ -32,100 +32,125 @@
#define sSVM "\xFC"
#define sTM "\xFB"
#define DYN_OK 0
#define DYN_ERR -1
enum {
DYN_OK = 0, // attention, DYN_OK doit etre egal a 0 sinon des tests seront KO...
DYN_ERR = -1,
#define DYN_FALSE 0
#define DYN_TRUE -1
DYN_FALSE = 0,
DYN_TRUE = -1,
#define DYN_LGNONE -1 // quand un parametre ne doit pas etre pris en compte, de type "lgChaine"
#define DYN_NONE 0 // quand un parametre ne doit pas etre pris en compte, de type "numChamp/numSousChamp separateurChamp/SousChamp"
DYN_LGNONE = -1, // quand un parametre ne doit pas etre pris en compte, de type "lgChaine"
DYN_NONE = 0, // quand un parametre ne doit pas etre pris en compte, de type "numChamp/numSousChamp separateurChamp/SousChamp"
#define DYN_ALL 0 // toues les occurences (dynChange...)
DYN_ALL = 0, // toues les occurences (dynChange...)
#define DYN_SORT_ASC 1
#define DYN_SORT_DESC 2
DYN_SORT_ASC = 1,
DYN_SORT_DESC = 2,
DYN_NOTFOUND = -1 // quand pas trouve (index...)
};
/*typedef struct
{
long mLg, mLgmax, mInternal;
char * mPtr;
short codePage;
} Dynamic;*/
typedef var Dynamic;
#define DYN_LGMIN 256
/*
pour la gestion de l'UTF8, revoir les methodes suivantes :
getLen, count, substr, erase, convert, cut
pour la gestion de l'UTF8, revoir les methodes suivantes (https://en.wikipedia.org/wiki/UTF-8) :
getLen, count, substr [x,y], erase, convert, cut
(+ version de getLen sur une chaine sz ; getLen doit remplacer l'utilisation de mLg dans certains cas / creer un getCharLen)
travailler en lg physique dans dynamic.c (c'est le cas) et si utf-8, faire un "pre-traitement" pour retrouver la lg physique
à partir de la lg "logique" quand besoin ; si pas possible, evo dans chaque methode de dynamic.c ou plutot faire une 2eme methode pour l'UTF8 !!
si erreur de codage/lecture utf8, la norme est de le remplacer par le point de code \uFFFD (EF BF BD) et de continuer (à convertir en 3F ? par exemple en mono byte)
*/
#include "apidecl.h"
/* ********************************************** */
void NumberToSz(env * e, ent64s valeur, char * resultat, long * lg);
char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
char * Int32ToSz(ent32s valeur, long signe, long leftPad);
long dynInit(env * e, Dynamic * this, long lgmax);
long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
void dynFree(env * e, Dynamic * this);
void dynSetLen(env * e, Dynamic * this, long lg);
long dynLgU8(env * e, Dynamic * this);
long dynCtrl(env * e, Dynamic * this, long lg, long copier);
void Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
void UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
long dynSetAsSz(env * e, Dynamic * this, char * chaine);
long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
long dynRead(env * e, Dynamic * this, char * fichier);
long dynWrite(env * e, Dynamic * this, char * fichier);
ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
ent64s dynToNumber(env * e, Dynamic * this);
long dynConvertError(env * e, Dynamic * this);
long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
void dynBegin(env * e, Dynamic * this);
long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
long dynConvert(env * e, Dynamic * this, char * from, char * to);
void dynReplace(env * e, Dynamic * this, char from, char to);
void dynErase(env * e, Dynamic * this, char * car);
long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
long dynConvertHexaToLong(Dynamic * valeur);
long dynConvertCharHexaToChar(char c1, char c2, char * c);
long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg);
long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadrage, char filler, long lg);
long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option);
WAPIDECL char * NumberToSz(env * e, ent64s valeur, char * resultat, ent64s * lg);
WAPIDECL char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
WAPIDECL char * Int32ToSz(ent32s valeur, long signe, long leftPad);
WAPIDECL long dynInit(env * e, Dynamic * this, long lgmax);
WAPIDECL long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
WAPIDECL void dynFree(env * e, Dynamic * this);
WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg);
//long dynCarU8(env * e, Dynamic * this, long * pos);
//long dynLgU8(env * e, Dynamic * this);
WAPIDECL long dynLengthUtf8(const char * p, long lg, int separator);
WAPIDECL long dynNextUtf8(char ** p, long lg, long * pos, char * carU8, int separator);
WAPIDECL long dynCtrl(env * e, Dynamic * this, long lg, long copier);
WAPIDECL long Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL long UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
WAPIDECL void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
WAPIDECL long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
WAPIDECL long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
WAPIDECL long dynSetAsSz(env * e, Dynamic * this, char * chaine);
WAPIDECL long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
WAPIDECL long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
WAPIDECL long dynRead(env * e, Dynamic * this, char * fichier);
WAPIDECL long dynWrite(env * e, Dynamic * this, char * fichier);
WAPIDECL ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
WAPIDECL ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
WAPIDECL ent64s dynToNumber(env * e, Dynamic * this);
WAPIDECL long dynConvertError(env * e, Dynamic * this);
WAPIDECL long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
WAPIDECL long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
WAPIDECL long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
WAPIDECL long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
WAPIDECL ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
WAPIDECL long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
WAPIDECL ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
WAPIDECL ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
WAPIDECL long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
WAPIDECL long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
WAPIDECL long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
WAPIDECL void dynBegin(env * e, Dynamic * this);
WAPIDECL long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
WAPIDECL long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
WAPIDECL long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynCountUtf8(env * e, Dynamic * this, char * caractere4, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSetSubstrUtf8(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSubstrUtf8(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
WAPIDECL long dynConvert(env * e, Dynamic * this, char * from, char * to);
WAPIDECL void dynReplace(env * e, Dynamic * this, char from, char to);
WAPIDECL long dynConvertUtf8(env * e, Dynamic * this, char * from, char * to);
WAPIDECL void dynErase(env * e, Dynamic * this, char * car);
WAPIDECL void dynEraseUtf8(env * e, Dynamic * this, char * car);
WAPIDECL long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
WAPIDECL long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
WAPIDECL long dynIndexSzUtf8(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
WAPIDECL long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
WAPIDECL long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
WAPIDECL char * dynConvertCharToCharHexa(octet c);
WAPIDECL long dynConvertHexaToLong(Dynamic * valeur);
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c);
WAPIDECL long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg);
WAPIDECL long dynFmtUtf8(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char * filler, long lg);
WAPIDECL long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadrage, char filler, long lg);
WAPIDECL long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option);
WAPIDECL long dynTrimUtf8(env * e, Dynamic * this, Dynamic * resultat, char * car, long option);
WAPIDECL long dynCleanString(env * e, Dynamic * this, octet debut, octet fin, long convHexa);
WAPIDECL void dynCleanHexaMark(env * e, Dynamic * this);
/* ********************************************** */
#endif
+36
View File
@@ -0,0 +1,36 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
typedef struct {
int dum;
} modContextEncod;
WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat);
+233
View File
@@ -0,0 +1,233 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "encod.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/* ****** PRIVATE ************************ */
static char hexa[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 128 cars a la fin de cette ligne */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
static char carhex[16] = {"0123456789abcdef"};
// TODO static char carHEX[16] = {"0123456789ABCDEF"};
static char base64[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* '+' = 62 ; '/' = 63 ; '-' (62) se trouve au milieu entre les deux */
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,99,-1,-1, /* '=' mis a 99 */
-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* dernier -1 ici = '_' (63) */
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 128 cars a la fin de cette ligne */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; // "=" mis a 99
static char carBase64[65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}; /* et caractere "=" en complement */
// TODO static char carBase64url[65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="}; /* et caractere "=" en complement */
/* TODO compatible UTF8 !! */
/* ****** PUBLIC ************************ */
WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat)
{
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
if(dynCtrl(e, resultat, this->mLg * 2, DYN_FALSE)) /* chaine hexa : taille double de celle origine */
return DYN_ERR;
long from = this->mLg - 1;
long to = from * 2 + 1;
/* cette methode fonctionne aussi si this et resultat pointent sur la meme variable... mettre TRUE dans dynCtrl alors ! */
for( ;from >= 0; )
{
resultat->mPtr[to--] = carhex[this->mPtr[from] % 16];
resultat->mPtr[to--] = carhex[this->mPtr[from--] / 16];
}
dynSetLen(e, resultat, this->mLg * 2);
return DYN_OK;
}
WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat)
{
/* conversion en base64 /base64url */
/* 3 cars en clair en donne 4 en base 64 ; si le dernier bloc contient 2 cars, la sortie est de 3 cars */
/* + car "=" ; si le dernier bloc contient 1 car, la sortie est de 2 cars + deux cars "=" */
/* quand le dernier bloc contient 1 ou 2 cars, les bits manquants pour avoir des octets complets sont mis a 0 */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
/* */
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
long lg64 = this->mLg / 3;
if(this->mLg % 3 != 0)
lg64++;
lg64 *= 4; // longueur finale du base64
if(dynCtrl(e, resultat, lg64, DYN_FALSE))
return DYN_ERR;
/* */
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 3)
{
if(from + 1 >= this->mLg)
{
/* bloc de 1 octet => 2 cars en sortie + 2 cars de complement */
resultat->mPtr[to++] = carBase64[this->mPtr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->mPtr[from] & 3) << 4)];
resultat->mPtr[to++] = carBase64[64];
resultat->mPtr[to++] = carBase64[64];
/* */
} else if(from + 2 >= this->mLg)
{
/* bloc de 2 octets => 3 cars en sortie + 1 car en complement */
resultat->mPtr[to++] = carBase64[this->mPtr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->mPtr[from] & 3) << 4) | (this->mPtr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->mPtr[from + 1] & 15) << 2)];
resultat->mPtr[to++] = carBase64[64];
}
else
{
/* bloc de 3 octets => 4 cars en sortie */
resultat->mPtr[to++] = carBase64[this->mPtr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->mPtr[from] & 3) << 4) | (this->mPtr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->mPtr[from + 1] & 15) << 2) | (this->mPtr[from + 2] >> 6)];
resultat->mPtr[to++] = carBase64[this->mPtr[from + 2] & 63];
}
}
/* */
dynSetLen(e, resultat, lg64);
return DYN_OK;
}
WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat)
{
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
if(this->mLg % 2 != 0)
return DYN_ERR; /* erreur format hexa incorrect */
if(dynCtrl(e, resultat, this->mLg / 2, DYN_FALSE))
return DYN_ERR;
/* */
char c1, c2;
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 2)
{
if((c1 = hexa[this->mPtr[from]]) == -1 || (c2 = hexa[this->mPtr[from + 1]]) == -1)
return DYN_ERR; /* erreur format hexa incorrect */
resultat->mPtr[to++] = (c1 << 4) | c2;
}
dynSetLen(e, resultat, this->mLg / 2);
return DYN_OK;
}
WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat)
{
/* conversion en clair de la chaine en base64 */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
if(this->mLg % 4 != 0)
return DYN_ERR; /* erreur format base64 incorrect */
long lgClair = (this->mLg / 4) * 3;
if(dynCtrl(e, resultat, lgClair, DYN_FALSE))
return DYN_ERR;
/* */
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 4, to += 3)
{
char c1 = base64[this->mPtr[from]];
char c2 = base64[this->mPtr[from + 1]];
char c3 = base64[this->mPtr[from + 2]];
char c4 = base64[this->mPtr[from + 3]];
if(c1 == -1 || c2 == -1 || c3 == -1 || c4 == -1 || c1 == 99 || c2 == 99 || (c3 == 99 && c4 != 99))
return DYN_ERR; /* erreur format base64 incorrect */
if(c4 == 99 && from + 4 < this->mLg)
return DYN_ERR; /* '=' autorise en fin de chaine uniquement */
//
resultat->mPtr[to] = 0;
resultat->mPtr[to + 1] = 0;
resultat->mPtr[to + 2] = 0;
resultat->mPtr[to] = c1 << 2;
resultat->mPtr[to] |= c2 >> 4;
if(c3 != 99)
{
resultat->mPtr[to + 1] = (c2 & 15) << 4;
resultat->mPtr[to + 1] |= c3 >> 2;
if(c4 != 99)
{
resultat->mPtr[to + 2] = (c3 & 3) << 6;
resultat->mPtr[to + 2] |= c4;
}
else
lgClair--;
}
else
lgClair--;
}
dynSetLen(e, resultat, lgClair);
return DYN_OK;
}
+20 -18
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -20,30 +20,32 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
enum {
/* types de requete FCGI */
#define FCGI_BEGIN_REQUEST 1
#define FCGI_ABORT_REQUEST 2
#define FCGI_END_REQUEST 3
#define FCGI_PARAMS 4
#define FCGI_STDIN 5
#define FCGI_STDOUT 6
FCGI_BEGIN_REQUEST = 1,
FCGI_ABORT_REQUEST = 2,
FCGI_END_REQUEST = 3,
FCGI_PARAMS = 4,
FCGI_STDIN = 5,
FCGI_STDOUT = 6,
/* demande dans le BEGIN REQUEST */
#define FCGI_RESPONDER 1
#define FCGI_AUTHORIZER 2
#define FCGI_FILTER 3
FCGI_RESPONDER = 1,
FCGI_AUTHORIZER = 2,
FCGI_FILTER = 3,
/* code du "protocl status" lors du END REQUEST */
#define FCGI_REQUEST_COMPLETE 0
#define FCGI_CANT_MPX_CONN 1
#define FCGI_OVERLOADED 2
#define FCGI_UNKNOWN_ROLE 3
FCGI_REQUEST_COMPLETE = 0,
FCGI_CANT_MPX_CONN = 1,
FCGI_OVERLOADED = 2,
FCGI_UNKNOWN_ROLE = 3,
/* codes d'erreurs du module */
#define WFC_OK 0 /* continuer a lire */
#define WFC_ERR 1
#define WFC_KEEPALIVE 2
#define WFC_REPONDRE 3
WFC_OK = 0, /* continuer a lire */
WFC_ERR = 1,
WFC_KEEPALIVE = 2,
WFC_REPONDRE = 3
};
/* Descritpion du message en cours ; id = 0 si aucun en cours */
struct {
+80 -69
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -26,10 +26,10 @@
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/types.h>
#else
#include "windows.h" // pour les fonctions FindFile...
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
@@ -51,13 +51,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -74,17 +73,24 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
// set : ecrit depuis param le dynamic dans le fichier (param = nom FM contenu)
// size : donne la taille sur disque du fichier
// dir : donne la liste des fichiers et repertoires d'un repertoire
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -97,40 +103,42 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
//*** code specifique ici
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); // version 1 ici
else if(param->type == VAR_NUMBER)
param->num = NUM_UN;
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "create", 6) == 0)
else if(modFnIs(e, "create", 6))
{
// todo...
// test
@@ -140,59 +148,61 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
printf("mod create %d\n", p_etat->error);
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
/* utilisation de dynRead qui fait le travail */
if(param->type == VAR_DYNAMIC)
/* utilisation de dynRead qui fait le travail, param1 : nom, param2 : contenu lu */
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynRead(e, param, param->mPtr) != DYN_OK)
if(dynRead(e, param2, param1->mPtr) != DYN_OK)
exc = setError(p_etat, 1);
}
else
exc = EX_MODPARAM; /* TODO code */
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "set", 3))
{
/* copie du code de dynWrite, avec modif car c'est la meme var dyn qui contient nom + contenu */
FILE * fic;
ent64s lg;
/* */
dynRemove(e, param, 0, 0, TRUE);
if(dynRemove(e, param, &e->int_dynamic, cFM, FALSE) < 0)
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
/* copie du code de dynWrite, avec modif param1 : nom, param2 : contenu a ecrire */
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
lg = e->int_dynamic.mInternal + 1;
#ifndef UNIX
if((fic = fopen(e->int_dynamic.mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(e->int_dynamic.mPtr, "w")) == NULL)
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fwrite(param->mPtr + lg, param->mLg - lg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
FILE * fic;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "w")) == NULL)
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
fclose(fic);
}
else
{
if(fwrite(param2->mPtr, param2->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "size", 4) == 0)
else if(modFnIs(e, "size", 4))
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
/* */
if(param->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
#ifndef UNIX
if((fic = fopen(param->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
if((fic = fopen(param1->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param->mPtr, "w")) == NULL)
if((fic = fopen(param1->mPtr, "r")) == NULL)
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
else
@@ -202,36 +212,37 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
else
{
lg = ftell(fic); /* longueur du fichier */
NumberToSz(e, lg, param->mPtr, (long *)&param->mLg); // TODO a verifier
param2->num = lg * NUM_FACTEUR;
}
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "dir", 3) == 0)
else if(modFnIs(e, "dir", 3))
{
/* copie du code de dynRead, plus court */
/* */
if(param->type != VAR_DYNAMIC)
if(param1 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef UNIX
DIR * rep = NULL;
if((rep = opendir(param->mPtr)) == NULL)
if((rep = opendir(param1->mPtr)) == NULL)
exc = setError(p_etat, 1); /* todo vraie erreur */
else
{
dynSetLen(e, param, 0); // idem raz
dynSetLen(e, param1, 0); // idem raz
struct dirent * fic = NULL;
while ((fic = readdir(rep)) != NULL)
{
if((fic->d_type == DT_DIR || fic->d_type == DT_REG) && strcmp(fic->d_name,".") != 0 && strcmp(fic->d_name,"..") != 0)
{
if(param->mLg > 0)
dynConcatSz(e, param, sFM, 1);
dynConcatSz(e, param, fic->d_name, DYN_LGNONE);
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, fic->d_name, DYN_LGNONE);
}
}
/* */
@@ -240,17 +251,17 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
#else
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
dynConcatSz(e, param, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(param->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
dynConcatSz(e, param1, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(param1->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
{
dynSetLen(e, param, 0); // idem raz
dynSetLen(e, param1, 0); // idem raz
for(int cr = -1;cr != 0;)
{
if(strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
{
if(param->mLg > 0)
dynConcatSz(e, param, sFM, 1);
dynConcatSz(e, param, FindFileData.cFileName, DYN_LGNONE);
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, FindFileData.cFileName, DYN_LGNONE);
}
cr = FindNextFile(hFind, &FindFileData);
}
+41 -14
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,7 +27,7 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
env e;
@@ -49,7 +49,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20
return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30
continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40
new,41,class,42,this,43,parent,44,free,45,precision,46,setsep,47,int,48,frac,49,abs,50
new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50
neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60
format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70
lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80
@@ -61,7 +61,7 @@ struct {
ent16 sub,endsub,if_,then,else_,elseif,endif,do_,call,invoke;
ent16 return_,returnon,loop,endloop,foreach,in,like,endfor,break_,breakon;
ent16 continue_,continueon,nop,part,echonl,echo,input,declare,let,delet;
ent16 new,class,this,parent,free,precision,setsep,int_,frac,abs;
ent16 new,class,this,parent,hold,precision,setsep,int_,frac,abs;
ent16 neg,round,type,len,count,dcount,field,index,search,change;
ent16 format,insert,remove,tonum,tostring,equal,diff,gt,lt,gte;
ent16 lte,and,or,not,beginpar,endpar,beginh,endh,begins,ends;
@@ -119,7 +119,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.class = rg(e, regles, "class", tmp);
r.this = rg(e, regles, "this", tmp);
r.parent = rg(e, regles, "parent", tmp);
r.free = rg(e, regles, "free", tmp);
r.hold = rg(e, regles, "hold", tmp);
r.precision = rg(e, regles, "precision", tmp);
r.setsep = rg(e, regles, "setsep", tmp);
r.int_ = rg(e, regles, "int", tmp);
@@ -181,17 +181,32 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.other = rg(e, regles, "other", tmp);
}
enum {
TAB_COUNT = 3,
COMMENT_EOL = 8
};
static void formatage_asm(Dynamic * s, Dynamic * f)
{
// TODO
}
static void formatage(Dynamic * s, Dynamic * f, int type)
{
// s : source ; f : source apres formatage, type : 1 w, 2 pcode
if(type == 2)
{
formatage_asm(s, f);
return;
}
//Dynamic token; /* contient les tokens suite au decodage lex d'une ligne */
ent16 tok; //,tok2,tok3; /* token lu par la macro ci-dessous "nreg" */
long n; /* indice en cours dans les token (parametre de la macro "nreg") base 1 */
//#define nreg(x) ((x)*2 > token.mLg ? 0 : *(ent16 *)(token.mPtr + (x)*2 - 2))
#define ntok(x) dynExtractSubFieldAsNumber(&e, &valex, 2, x, &tmp)
//
#define TAB_COUNT 3
#define COMMENT_EOL 8
//#define TAB_COUNT 3
//#define COMMENT_EOL 8
//
Dynamic trav, tmp, lig; /* variables de travail */
Dynamic regles; /* regles lex */
@@ -199,7 +214,8 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
//
dynInit(&e, &regles, 0);
//
if(lire_regles_lex(&e, &regles, "/etc/wlanguage/wlex") != DYN_OK) // au lieu de lex/wlex
//if(lire_regles_lex(&e, &regles, "/etc/wlanguage/wlex") != DYN_OK) // au lieu de lex/wlex
if(lire_regles_lex(&e, &regles, "wlex") != DYN_OK)
{
dynLet(&e, f, s->mPtr, s->mLg);
dynFree(&e, &regles);
@@ -313,14 +329,25 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
//if(tok2 != r.comment)
// pos_comment = -1;
}
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 10 (par exemple), >= position actuelle
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 8, >= position actuelle
// + formatage debut de ligne
if(pos_comment == -1)
dynSubstr(&e, &trav, &lig, pos - 1, (long)trav.mPtr - pos, 1, DYN_NONE, 10, DYN_NONE);
{
#ifdef WINLIB
dynSubstr(&e, &trav, &lig, pos - 1, ((intptr_t)(trav.mPtr)) - pos, 1, DYN_NONE, 10, DYN_NONE);
#else
dynSubstr(&e, &trav, &lig, pos - 1, (long)(trav.mPtr - pos), 1, DYN_NONE, 10, DYN_NONE);
#endif
}
else
{
dynSubstr(&e, &trav, &lig, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
dynSubstr(&e, &trav, &tmp, pos_comment - 1, (long)trav.mPtr - pos_comment, 1, DYN_NONE, 10, DYN_NONE);
dynSubstr(&e, &trav, &tmp, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
dynTrim(&e, &tmp, &lig, ' ', 2);
#ifdef WINLIB
dynSubstr(&e, &trav, &tmp, pos_comment - 1, ((intptr_t)(trav.mPtr)) - pos_comment, 1, DYN_NONE, 10, DYN_NONE);
#else
dynSubstr(&e, &trav, &tmp, pos_comment - 1, (long)(trav.mPtr - pos_comment), 1, DYN_NONE, 10, DYN_NONE);
#endif
}
//
if(flag_trt == 1)
@@ -382,7 +409,7 @@ int main(int argc, char * argv[])
type = 1; // par defaut formatage du source w
else if(argc != 3)
{
printf("Usage: wlf [-w|-wa] <source>\n");
printf("Usage: lwf [-w|-wa] <source>\n");
exit(-1);
}
else
@@ -394,7 +421,7 @@ int main(int argc, char * argv[])
type = 2; // formatage du pcode (fichier .wa) TODO
else
{
printf("Usage: wlf [-w|-wa] <source>\n");
printf("Usage: lwf [-w|-wa] <source>\n");
exit(-1);
}
}
+217
View File
@@ -0,0 +1,217 @@
begin gened
;
class Gened = {Base}
;
let Gened.trace = @false
;
let Gened.name = ''
let Gened.query = ''
;
let Gened.breakInfo = ''
let Gened.breakCount = 0
;
let Gened.recordCount = 0
let Gened.init = @true
let Gened.first = @true
let Gened.last = @false
let Gened.currentRecord = ''
let Gened.precRecord = ''
;
; breakInfo, champs en multi-valeurs :
let Gened.BREAKFIELDNUM = 1 ; {1} = num champ dans l'enregistrement
let Gened.BREAKFIELDVAL = 2 ; {2} = valeur champ enreg en cours
let Gened.BREAKFIELDVALPREC = 3 ; {2} = valeur champ enreg en cours
let Gened.BREAKDIFF = 4 ; {4} = flag si difference pour ce niveau
let Gened.BREAKCOUNTER = 5 ; {5} = compteur d'enregs pour ce niveau de rupture
;
sub Gened.ParamSection()
; maj de name/query/breakInfo{1}
if this.trace then
echonl "ED => in ParamSection"
endif
except
endsub
;
sub Gened.SetQuery()
; creer la requete de recuperation des enregistrements (utilise query)
if this.trace then
echonl "ED => in SetQuery"
endif
except
endsub
;
sub Gened.GetNextRecord()
; recupere l'enregistrement suivant, et l'ecrit dans this.currentRecord et this.last = @false, sinon this.last = @true et this.currentRecord = ''
if this.trace then
echonl "ED => in GetNextRecord"
endif
except
endsub
;
sub Gened.EndOfQuery()
; terminer la requete de recup. des enregistrements
if this.trace then
echonl "ED => in EndOfQuery"
endif
except
endsub
;
sub Gened.InitSection()
if this.trace then
echonl "ED => in InitSection"
endif
except
endsub
;
sub Gened.DoSection()
if this.trace then
echonl "ED => in DoSection, record #23":this.recordCount:' => ':this.currentRecord
endif
except
endsub
;
sub Gened.EndSection()
if this.trace then
echonl "ED => in EndSection"
endif
except
endsub
;
sub Gened.LevelBreakHeader(level)
if this.trace then
echonl "ED => in LevelBreakHeader:":level:' ':field(this.breakInfo{this.BREAKFIELDVAL, level}, "#FC", level)
endif
except
endsub
;
sub Gened.LevelBreakFooter(level)
if this.trace then
echonl "ED => in LevelBreakFooter:":level:' ':field(this.breakInfo{this.BREAKFIELDVALPREC, level}, "#FC", level):' last(':this.last:')'
endif
except
endsub
;
sub Gened.Execute()
declare un, moinsUn, breakVal, breakNum ; compteur des niveaux de rupture
let un = 1
let moinsUn = neg(1)
declare SVM
let SVM = "#FC"
let breakVal = ''
let breakNum = 0
;
do this.ParamSection()
;
do this.SetQuery()
;
do this.GetNextRecord()
;
let this.recordCount = 0
let this.breakCount = dcount(this.breakInfo, this.BREAKFIELDNUM)
;
do this.InitSection()
;
if not(this.last) then
loop
breakon this.last
if not(this.init) then
do this.GetNextRecord()
else
let this.init = @false
endif
;
foreach breakNum in un, this.breakCount
let breakVal = this.currentRecord{ this.breakInfo{this.BREAKFIELDNUM, breakNum} }
if breakNum > un then
let breakVal = this.breakInfo{this.BREAKFIELDVAL, breakNum - 1}:SVM:breakVal
endif
let this.breakInfo{this.BREAKFIELDVAL, breakNum} = breakVal
let this.breakInfo{this.BREAKDIFF, breakNum} = (this.breakInfo{this.BREAKFIELDVALPREC, breakNum} # breakVal)
endfor
;
if this.breakCount > 0 and (this.first or this.last or this.breakInfo{4, this.breakCount}) then
if not(this.first) then
foreach breakNum in this.breakCount, un, moinsUn
if this.last or this.breakInfo{this.BREAKDIFF, breakNum} then
do this.LevelBreakFooter(breakNum)
endif
endfor
endif
if not(this.last) then
foreach breakNum in un, this.breakCount
if this.first or this.breakInfo{this.BREAKDIFF, breakNum} then
let this.breakInfo{this.BREAKCOUNTER, breakNum} = 0
do this.LevelBreakHeader(breakNum)
endif
endfor
endif
let this.first = @false
endif
;
if not(this.last) then
foreach breakNum in un, this.breakCount
let this.breakInfo{this.BREAKCOUNTER, breakNum} = this.breakInfo{this.BREAKCOUNTER, breakNum} + 1
endfor
let this.recordCount = this.recordCount + 1
;
do this.DoSection()
;
let this.precRecord = this.currentRecord
let this.breakInfo{this.BREAKFIELDVALPREC} = this.breakInfo{this.BREAKFIELDVAL}
endif
endloop
endif
;
do this.EndSection()
;
do this.EndOfQuery()
;
except
; TODO
echonl "Exception in Execute"
endsub
;
class EdTest = {Gened}
;
sub EdTest.SetQuery()
declare path
let path = 'data.txt'
let this.data = ''
let this.line = 0
;
invoke file&get(path, this.data)
let this.data = change(this.data, '#0A', @fm)
;
let this.breakInfo = "3":@vm:5
;
do parent.SetQuery
except
endsub
;
sub EdTest.InitSection()
;echonl 'nb break: ':this.breakCount
do parent.InitSection
except
endsub
;
sub EdTest.GetNextRecord()
let this.line = this.line + 1
let this.currentRecord = this.data{this.line}
if this.currentRecord = '' then
let this.last = @true
else
let this.currentRecord = change(this.currentRecord, ';', @fm)
endif
;echonl "EdTest GetNextRecord: ":this.last:' / line ':this.line:' => ':this.currentRecord
except
endsub
;
declare ed
let ed = new EdTest
let ed.trace = @true
do ed.Execute()
;
except
;
echonl "Exception in main: ":@except
end
+19 -211
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,213 +27,10 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
env e;
long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, 10);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, 10, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
struct {
long blanc, nomregle, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} r;
void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
{
r.blanc = rg(e, regles, "blanc", tmp); // 1
r.nomregle = rg(e, regles, "nomregle", tmp); // 2
r.debut = rg(e, regles, "debut", tmp); // 3
r.fin = rg(e, regles, "fin", tmp); // 4
r.occ = rg(e, regles, "occ", tmp); // 5
r.infini = rg(e, regles, "infini", tmp); // 6
r.commentaire = rg(e, regles, "commentaire", tmp); // 7
r.intervalle = rg(e, regles, "intervalle", tmp); // 8
r.hexa = rg(e, regles, "hexa", tmp); // 9
r.car = rg(e, regles, "car", tmp); // 10
r.reste = rg(e, regles, "reste", tmp); // 11
}
long parse(Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours)
{
#define nreg(x) ((x)*2 > trav->mLg ? 0 : *(ent16 *)(trav->mPtr + (x)*2 - 2))
/* */
static int numlig = 0;
numlig++;
/* */
if(valex->mLg == 0)
return OK; /* ligne vide */
/* */
int nbres = dynDcount(&e, resultat, 10, DYN_NONE, DYN_NONE);
int nbval = dynDcount(&e, valex, cVM, 2, cFM);
ent16 regle;
dynSetLen(&e, trav, 0);
dynSetLen(&e, encours, 0);
for(int ival = nbval; ival > 0; ival--)
{
/* suppression des regles 1 et 7 (blanc et commentaire) */
dynField(&e, valex, tmp, 2, ival, cFM, cVM, 1);
regle = dynToNum(&e, tmp, DYN_FALSE, 0);
if(regle == r.blanc || regle == r.commentaire)
{
dynDel(&e, valex, 1, ival, cFM, cVM, 1);
dynDel(&e, valex, 2, ival, cFM, cVM, 1);
dynDel(&e, valex, 3, ival, cFM, cVM, 1);
}
else
{
if(dynCtrl(&e, trav, trav->mLg + 2, TRUE) != DYN_OK)
return DYN_ERR;
if(trav->mLg > 0)
memcopie(trav->mPtr + 2, trav->mPtr, trav->mLg);
*(ent16 *)(trav->mPtr) = regle;
dynSetLen(&e, trav, trav->mLg + 2);
}
}
//dynDel(&e, valex, 2, DYN_NONE, cFM, DYN_NONE, 1);
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
//for(int i=1;i<=trav->mLg/2;i++) printf("%d,",nreg(i)); printf("\n");
/* debut d'analyse des tokens : nomregle */
if(nreg(1) != r.nomregle)
{
dynField(&e, valex, tmp, 3, 1, cFM, cVM, 1);
printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* liste de et/ou */
for(ent16 n = 2;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == r.debut || regle == r.car) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : car ou debut et/ou attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* et */
if(n == 2)
dynStoreSz(&e, valex, 4, DYN_NONE, "", 0, cFM, DYN_NONE);
else
dynConcatSz(&e, valex, ";", 1);
/* */
if(regle == r.car)
{
/* 1 caractere = (1,1,car) (raccourci d'ecriture) */
dynConcatSz(&e, valex, "1,1,", 4);
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(&e, valex, tmp);
n++;
continue;
}
if(nreg(n+1) == r.occ && (nreg(n+2) == r.occ || nreg(n+2) == r.infini)) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : occurence min/max attendue %d\n", numlig, tmp->mPtr, n);
return DYN_ERR;
}
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcat(&e, valex, encours); // occmin
n++;
if(nreg(n) == r.infini)
dynConcatSz(&e, valex, "-1,", 3);
else
{
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcat(&e, valex, encours); // occmax
}
ent16 n1,n2,n3; char unefois[2] = {0};
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
while(n1 == r.car || n1 == r.hexa || ((n1 == r.car || n1 == r.hexa) && n2 == r.intervalle && (n3 == r.car || n3 == r.hexa)))
{
dynConcatSz(&e, valex, unefois, DYN_LGNONE);
if((n1 == r.car || n1 == r.hexa) && n2 == r.intervalle && (n3 == r.car || n3 == r.hexa))
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
if(n1 == 10)
dynConcat(&e, valex, tmp);
else
{
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
dynConcatSz(&e, valex, "-", 1);
n += 2;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
if(n3 == r.car)
dynConcat(&e, valex, tmp);
else
{
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
}
else if(n1 == r.car)
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(&e, valex, tmp);
}
else if(n1 == r.hexa)
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
unefois[0] = ':';
}
if(unefois[0] == 0)
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : caractere/intervalle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
if(n1 == r.fin) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : fin et/ou attendue\n", numlig, tmp->mPtr);
return DYN_ERR;
}
n += 2;
}
/* lecture nom regle en hexa */
dynField(&e, valex, tmp, 1, 1, cFM, cVM, 1);
dynIconv(&e, tmp, trav, "X");
trav->mPtr[trav->mLg - 1] = ','; /* exemple : begin,1,comment,2,... permet de faire un locate */
dynConcatSz(&e, trav, Int64ToSz(&e, nbres == 0 ? 1 : nbres, DYN_FALSE, 0), DYN_LGNONE);
dynStore(&e, resultat, 1, nbres == 0 ? 1 : nbres*2-1, trav, 10, ',');
/* */
dynField(&e, valex, tmp, 4, DYN_NONE, cFM, DYN_NONE, 1);
nbres = (nbres == 0 ? 2 : nbres + 1);
dynStoreSz(&e, resultat, nbres, DYN_NONE, tmp->mPtr, tmp->mLg, 10, DYN_NONE);
/* */
#undef nreg
return OK;
}
long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3)
{
dynSetLen(&e, elem2, 0); // token
@@ -313,6 +110,13 @@ long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3
return OK;
}
long gen_h(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3)
{
dynErase(&e, resultat, "\r"); /* nettoyage au cas ou fichier Windows */
dynChange(&e, resultat, "\n", "\\n", DYN_ALL);
return OK;
}
int main(int argc, char * argv[])
{
Dynamic fichier, valex, ligne, resultat, elem1, elem2, elem3, regles;
@@ -321,7 +125,7 @@ int main(int argc, char * argv[])
/* argument : fichier lex a convertir en format "interne" */
if(argc != 2)
{
printf("Usage: genlex <fichier>\n");
printf("Usage: wlex <fichier>\n");
exit(-3);
}
/* */
@@ -343,13 +147,12 @@ int main(int argc, char * argv[])
}
else
{
if(lire_regles_lex(&e, &regles, NULL) != DYN_OK)
if(lire_regles_lex(&e, &regles, "lexlex") != DYN_OK)
ret = -3;
}
if(ret == 0)
{
init_reg(&e, &regles, &elem1);
//printf("commentaire : %ld nomregle : %ld\n", r.commentaire, r.nomregle);
init_reg_lex(&e, &regles, &elem1); // elem1 = var tmp
//
dynErase(&e, &fichier, "\r");
dynRemove(&e, &fichier, NULL, 0, DYN_TRUE);
@@ -357,18 +160,23 @@ int main(int argc, char * argv[])
{
lex(&e, &regles, &ligne, &valex);
/* */
ret = parse(&valex, &resultat, &elem1, &elem2, &elem3);
ret = parse_lex(&e, &valex, &resultat, &elem1, &elem2, &elem3);
/* */
//dynConvert(&e, &valex, sFM sVM, "\n|");
//printf("valex %s\n", valex.mPtr);//
}
printf("Resultat (ret=%d):\n%s\n", ret, resultat.mPtr);
dynFree(&e, &regles);
//
if(ret == 0)
{
dynLet(&e, &fichier, resultat.mPtr, resultat.mLg); // sauvegarde
// generer le code C a copier/coller dans genw.c
ret = gen_c(&resultat, &elem1, &elem2, &elem3);
printf("\nCode C genere : \n%s\n", resultat.mPtr);
//
// generer le code C a copier/coller dans lex_files.h
ret = gen_h(&fichier, &elem1, &elem2, &elem3);
printf("\nCode H genere : \n%s\n", fichier.mPtr);
}
}
dynFree(&e, &valex);
+627 -312
View File
File diff suppressed because it is too large. Load diff
+99 -43
View File
@@ -25,10 +25,19 @@
#include <string.h>
#include "langage.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
#ifndef WINLIB
/* met a jour le minimum de <env> pour pouvoir utiliser <dynamic.h> sans erreur... */
void init_env(env * e)
WAPIDECL void init_env(env * e)
{
int i,j,k;
/* endianess */
@@ -56,7 +65,7 @@ void init_env(env * e)
e->sep_subfield = '\xFD'; // cVM
}
char * copy_nom(env * e, const char * s)
WAPIDECL char * copy_nom(env * e, const char * s)
{
e->nom64[0] = 0;
e->nom64[1] = 0;
@@ -67,35 +76,22 @@ char * copy_nom(env * e, const char * s)
return e->nom;
}
/* CONTENU DE env->g
_arg : contient en FM les arguments de la ligne de commande a partir du nom du pcode wp ; @ARG
_file : contient le fichier source en cours, arborescence en FM celui en cours toujours en <1> ; @FILE
_bin : contient les noms des progs pcode en cours, arborescence d'appel des library en VM att 1 + "position" (1-n) binaddr en VM att 2, prog principal puis chaque appel de libr,
si plusieurs appel de la meme libr, le nom est repete ! le nom memorise est sans chemin ni extension (WBIN + .wp ajoute en auto); @BIN
exemple : prog VM libA VM libA VM libB FM 1 VM 2 VM 2 VM 3
_binaddr : contient les adresses debut et fin et compteur des sub/libr (pour eviter SIGSEGV lors dechargement library)
_env : contient les variables d'environnement "WBIN" FM "WSRC" ; @ENV
_prog : contient le nom du programme (apres begin dans le source), pas le nom du fichier
__xxx : var subroutine point d'entree pour le module xxx (dlsym)
a b c : variables globales
classe1 : classes, hashtables contenant =>
_class, ce qui permet de differencier une hashtable simple d'une classe
t u v : membres de la classe
objet1 : objet, instanciation d'une classe contenant =>
_class (oid FM _class de la classe), pour se differencier d'une hashtable normale
_oid : dernier n° d'objet traite (new,...) var @OID
_local : cree lors d'un do, contient la hashtable des vars de la sub (peut elle meme contenir une var _local pour
la sub appelee depuis la sub, etc.). Contenu de _local =>
_stack : var memorisant ce qu'il faut pour revenir a l'appelant
x y z : variables locales
*/
WAPIDECL int modFnIs(env * e, const char * fn, int lg)
{
// modifier l'endroit ou e->fn est mis a jour : verif fn64[0 1 2] est bien remis a zero avant la maj
ent64 f[3];
f[0] = 0; f[1] = 0; f[2] = 0;
if(lg < 1 || lg > 23)
return FALSE;
strncpy((char *)f, fn, lg);
return (e->fn64[0] == f[0] && e->fn64[1] == f[1] && e->fn64[2] == f[2]);
}
/* ************************************************************************** */
/* fonctions wrapper au cas ou on aurait besoin de ne plus utiliser certaines */
/* fonctions standards (malloc, etc.) */
void * memalloc(env * e, ent64 taille)
WAPIDECL void * memalloc(env * e, ent64 taille)
{
void * ptr;
taille += sizeof(ent64);
@@ -109,7 +105,11 @@ void * memalloc(env * e, ent64 taille)
}
*(ent64 *)ptr = taille;
//printf("P%p+\n", ptr);
#ifdef UNIX
return(ptr + sizeof(ent64));
#else
return((pointeur)ptr + sizeof(ent64));
#endif
}
else
{
@@ -119,11 +119,15 @@ void * memalloc(env * e, ent64 taille)
}
}
void memfree(env * e, void * ptr)
WAPIDECL void memfree(env * e, void * ptr)
{
if(ptr != NULL)
{
ptr -= sizeof(ent64);
#ifdef UNIX
ptr -= sizeof(ent64);
#else
(pointeur)ptr -= sizeof(ent64);
#endif
if(e != NULL)
{
e->mem_numb--;
@@ -135,7 +139,7 @@ void memfree(env * e, void * ptr)
}
}
void memcopie(void * dst, void * src, long nb)
WAPIDECL void memcopie(void * dst, void * src, long nb)
{
if(dst == src || nb <= 0)
return;
@@ -153,7 +157,55 @@ void memcopie(void * dst, void * src, long nb)
// for (char *p=src, *q=dst; --n>=0; ) q[n]=p[n]; // fin au debut
}
void hex(pointeur ch, int lg)
WAPIDECL void dynPrintfSz(env * e, const char * format, char * valeur)
{
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
if(valeur)
dynChange(e, &e->printf, PRINTF_MARK, valeur, DYN_ALL);
}
WAPIDECL void dynPrintfInt64(env * e, const char * format, ent64s valeur, long nb)
{
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
dynChange(e, &e->printf, PRINTF_MARK, Int64ToSz(e, valeur, DYN_TRUE, nb), DYN_ALL);
}
WAPIDECL void dynPrintfHex(env * e, const char * format, ent64 valeur, long nb)
{
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
char conv[17] = "0000000000000000";
conv[16] = 0;
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
int i;
for(i = 15; i >=0 && valeur != 0; i--, valeur /= 16)
conv[i] = hex[valeur % 16];
//
if(nb > 0 && nb < 17)
nb = 16 - nb;
else
nb = i + 1;
dynChange(e, &e->printf, PRINTF_MARK, conv + nb, DYN_ALL);
}
WAPIDECL void dynPrintfConcatHexSz(env * e, char * valeur, long lg)
{
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
char car[3] = {0};
for(long i = 0; i < lg; i++)
{
car[0] = hex[((unsigned char)valeur[i]) >> 4];
car[1] = hex[((unsigned char)valeur[i]) & 15];
dynConcatSz(e, &e->printf, car, 2);
if(i % 32 == 31 && i < lg - 1)
dynConcatSz(e, &e->printf, "\n ", 4);
else if(i % 8 == 7 && i < lg - 1)
dynConcatSz(e, &e->printf, " | ", 3);
else
dynConcatSz(e, &e->printf, " ", 1);
}
}
WAPIDECL void hex(pointeur ch, int lg)
{
int i;
char c;
@@ -173,7 +225,7 @@ void hex(pointeur ch, int lg)
printf(" > %s\n", a);
}
void hex2(char * ch, int lg, int nbpl)
WAPIDECL void hex2(char * ch, int lg, int nbpl)
{
int i;
char c;
@@ -216,14 +268,18 @@ void hex2(char * ch, int lg, int nbpl)
printf(" (%6d) %s\n", i, a);
}
#else
// Windows...
void init_env(env * e) {}
void hex(pointeur ch, int lg) {}
void hex2(char * ch, int lg, int nbpl) {}
void memcopie(void * dst, void * src, long nb) {}
void memfree(env * e, void * ptr) {}
void * memalloc(env * e, ent64 taille) {}
#endif
WAPIDECL void hex3(const char * p, long lg)
{
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
// affiche en hexa la chaine sur une ligne
printf("=> ");
for(long i = 0; i < lg; i++)
{
printf("%c%c ", hex[((unsigned char)p[i]) >> 4], hex[((unsigned char)p[i]) & 15]);
if(i % 32 == 31 && i < lg - 1)
printf("\n ");
else if(i % 8 == 7 && i < lg - 1)
printf(" | ");
}
printf("\n");
}
+16 -31
View File
@@ -23,45 +23,30 @@
#ifndef GLOBAL_H
#define GLOBAL_H
#include "apidecl.h"
void init_env(env * e);
WAPIDECL void init_env(env * e);
char * copy_nom(env * e, const char * s);
/* CONTENU DE env->g
_arg : contient en FM les arguments de la ligne de commande a partir du nom du pcode wp ; @ARG
_file : contient le fichier source en cours, arborescence en FM celui en cours toujours en <1> ; @FILE
_bin : contient les noms des progs pcode en cours, arborescence d'appel des library en VM att 1 + "position" (1-n) binaddr en VM att 2, prog principal puis chaque appel de libr,
si plusieurs appel de la meme libr, le nom est repete ! le nom memorise est sans chemin ni extension (WBIN + .wp ajoute en auto); @BIN
exemple : prog VM libA VM libA VM libB FM 1 VM 2 VM 2 VM 3
_binaddr : contient les adresses debut et fin et compteur des sub/libr (pour eviter SIGSEGV lors dechargement library)
_env : contient les variables d'environnement "WBIN" FM "WSRC" ; @ENV
_prog : contient le nom du programme (apres begin dans le source), pas le nom du fichier
__xxx : var subroutine point d'entree pour le module xxx (dlsym)
a b c : variables globales
classe1 : classes, hashtables contenant =>
_class, ce qui permet de differencier une hashtable simple d'une classe
t u v : membres de la classe
objet1 : objet, instanciation d'une classe contenant =>
_class (oid FM _class de la classe), pour se differencier d'une hashtable normale
_oid : dernier n° d'objet traite (new,...) var @OID
_local : cree lors d'un do, contient la hashtable des vars de la sub (peut elle meme contenir une var _local pour
la sub appelee depuis la sub, etc.). Contenu de _local =>
_stack : var memorisant ce qu'il faut pour revenir a l'appelant
x y z : variables locales
*/
WAPIDECL char * copy_nom(env * e, const char * s);
WAPIDECL int modFnIs(env * e, const char * fn, int lg);
/* ************************************************************************** */
/* fonctions wrapper au cas ou on aurait besoin de ne plus utiliser certaines */
/* fonctions standards (malloc, etc.) */
void * memalloc(env * e, ent64 taille);
void memfree(env * e, void * ptr);
void memcopie(void * dst, void * src, long nb);
WAPIDECL void * memalloc(env * e, ent64 taille);
WAPIDECL void memfree(env * e, void * ptr);
WAPIDECL void memcopie(void * dst, void * src, long nb);
void hex(pointeur ch, int lg);
void hex2(char * ch, int lg, int nbpl);
#define PRINTF_MARK "\1"
WAPIDECL void dynPrintfSz(env * e, const char * format, char * valeur);
WAPIDECL void dynPrintfInt64(env * e, const char * format, ent64s valeur, long nb);
WAPIDECL void dynPrintfHex(env * e, const char * format, ent64 valeur, long nb);
WAPIDECL void dynPrintfConcatHexSz(env * e, char * valeur, long lg); // equiv hex3
WAPIDECL void hex(pointeur ch, int lg);
WAPIDECL void hex2(char * ch, int lg, int nbpl);
WAPIDECL void hex3(const char * p, long lg);
/* ************************************ */
#endif
+296 -42
View File
@@ -52,10 +52,10 @@ static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
return err == OK ? OK : EX_MODERR;
}
static void encodageMD2(char * entree, ent64 longueur, char * sortie)
static void encodageMD2(env * e, var * entree, var * sortie)
{
unsigned char checksum[16] = {0};
unsigned char padding[16] = {0};
@@ -74,8 +74,9 @@ static void encodageMD2(char * entree, ent64 longueur, char * sortie)
235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
unsigned char * p = (unsigned char *)entree;
unsigned char * p = (unsigned char *)(entree->ptr);
unsigned char L = 0, T;
long longueur = entree->mLg;
while(longueur >= 16)
{
for(i = 0; i < 16; i++)
@@ -131,13 +132,13 @@ static void encodageMD2(char * entree, ent64 longueur, char * sortie)
/* fin du calcul md2 : en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i = 0, j = 0; i < 16; i++)
{
sortie[j++] = carhex[buffer[i] / 16];
sortie[j++] = carhex[buffer[i] % 16];
sortie->ptr[j++] = carhex[buffer[i] / 16];
sortie->ptr[j++] = carhex[buffer[i] % 16];
}
sortie[j] = 0;
dynSetLen(e, sortie, j); // len = 32 ici
}
static void majMD4(unsigned int * md4, unsigned int * buffer)
static void majMD4(unsigned int * md4, pointeur buffer)
{
unsigned int A, B, C, D, tmp;
unsigned int buf[16];
@@ -150,7 +151,7 @@ static void majMD4(unsigned int * md4, unsigned int * buffer)
#define h(W,X,Y,Z,i,r) W = rot((W + (X^Y^Z) + buf[i] + 0x6ED9EBA1),r)
/* coder le buffer en little endian */
octet = (unsigned char *)buffer;
octet = buffer;
for(i=0; i<16; i++, octet+=4)
buf[i] = (*octet) | ((*(octet+1))<<8) | ((*(octet+2))<<16) | ((*(octet+3))<<24);
/* */
@@ -217,7 +218,7 @@ static void majMD4(unsigned int * md4, unsigned int * buffer)
md4[3] += D;
}
void encodageMD4(char * entree, ent64 longueur, char * sortie)
static void encodageMD4(env * e, var * entree, var * sortie)
{
unsigned char lg[8];
unsigned char buffer[64];
@@ -229,12 +230,14 @@ void encodageMD4(char * entree, ent64 longueur, char * sortie)
md4[1] = (unsigned int)0xefcdab89;
md4[2] = (unsigned int)0x98badcfe;
md4[3] = (unsigned int)0x10325476;
long longueur = entree->mLg;
*(ent64 *)lg = (ent64)longueur * 8;
/* */
pointeur p = entree->ptr;
while(longueur >= 64)
{
majMD4(md4, (unsigned int *)entree);
entree += 64;
majMD4(md4, p);
p += 64;
longueur -= 64;
}
/* traitement du dernier bloc */
@@ -242,7 +245,7 @@ void encodageMD4(char * entree, ent64 longueur, char * sortie)
/* si pas assez de place, faire un nouveau bloc */
memset(buffer, 0, 64);
if(longueur > 0)
memcpy(buffer, entree, longueur);
memcpy(buffer, p, longueur);
buffer[longueur] = 128; /* 0x80 */
if(longueur <= 55)
{
@@ -256,12 +259,12 @@ void encodageMD4(char * entree, ent64 longueur, char * sortie)
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, (unsigned int *)buffer);
majMD4(md4, buffer);
}
else
{
/* 2 derniers blocs */
majMD4(md4, (unsigned int *)buffer);
majMD4(md4, buffer);
/* */
memset(buffer, 0, 64);
// encoder la longueur en little endian
@@ -273,7 +276,7 @@ void encodageMD4(char * entree, ent64 longueur, char * sortie)
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, (unsigned int *)buffer);
majMD4(md4, buffer);
}
//
/* calcul md4 en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
@@ -281,33 +284,263 @@ void encodageMD4(char * entree, ent64 longueur, char * sortie)
{
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie[j] = carhex[buffer[0]/16];
sortie[j+1] = carhex[buffer[0]%16];
sortie->ptr[j] = carhex[buffer[0]/16];
sortie->ptr[j+1] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie[j+2] = carhex[buffer[0]/16];
sortie[j+3] = carhex[buffer[0]%16];
sortie->ptr[j+2] = carhex[buffer[0]/16];
sortie->ptr[j+3] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie[j+4] = carhex[buffer[0]/16];
sortie[j+5] = carhex[buffer[0]%16];
sortie->ptr[j+4] = carhex[buffer[0]/16];
sortie->ptr[j+5] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
sortie[j+6] = carhex[buffer[0]/16];
sortie[j+7] = carhex[buffer[0]%16];
sortie->ptr[j+6] = carhex[buffer[0]/16];
sortie->ptr[j+7] = carhex[buffer[0]%16];
}
sortie[32] = 0;
dynSetLen(e, sortie, 32);
}
#ifndef UNIX
/* MD5 stuff, as of RFC 1321 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
static void encodageMD5(env * e, var * entree, var * sortie)
{
ent32 a, b, c, d, s0, s1, s2, s3, i, x[16];
unsigned char buffer[64];
/* */
s0 = 0x67452301;
s1 = 0xefcdab89;
s2 = 0x98badcfe;
s3 = 0x10325476;
/* */
long len64 = entree->mLg % 64;
long nb64 = entree->mLg / 64;
long der1 = 0, der2 = 0, der3 = 0;
if(len64 < 56)
{
// dernier bloc : len64(entree) 1(128) 55-len64(0) 8(mLg)
der1 = ++nb64;
}
else
{
// avant dernier bloc : len64(entree) 1(128) 63-len64(0)
// dernier bloc : 0(56) 8(mLg)
der2 = ++nb64;
der3 = ++nb64;
}
ent64 nb = (ent64)(entree->mLg * 8); /* en bits */
pointeur p = entree->ptr;
/* pour chaque bloc de 64 octets (512 bits) */
for(long cpt = 1; cpt <= nb64; cpt++)
{
if(cpt == der1)
{
// dernier bloc cas modulo < 56
memset(buffer, 0, 64);
if(len64 > 0)
memcpy(buffer, p, len64);
buffer[len64] = 128;
buffer[56] = (nb) & 0xff;
buffer[57] = (nb >> 8) & 0xff;
buffer[58] = (nb >> 16) & 0xff;
buffer[59] = (nb >> 24) & 0xff;
buffer[60] = (nb >> 32) & 0xff;
buffer[61] = (nb >> 40) & 0xff;
buffer[62] = (nb >> 48) & 0xff;
buffer[63] = (nb >> 56) & 0xff;
p = buffer;
}
else if(cpt == der2)
{
// avant dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
memcpy(buffer, p, len64);
buffer[len64] = 128;
p = buffer;
}
else if (cpt == der3)
{
// dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
buffer[56] = (nb) & 0xff;
buffer[57] = (nb >> 8) & 0xff;
buffer[58] = (nb >> 16) & 0xff;
buffer[59] = (nb >> 24) & 0xff;
buffer[60] = (nb >> 32) & 0xff;
buffer[61] = (nb >> 40) & 0xff;
buffer[62] = (nb >> 48) & 0xff;
buffer[63] = (nb >> 56) & 0xff;
p = buffer;
}
/* deplier la boucle ? */
for (i = 0; i < 16; i++)
{
x[i] = ((ent32)(*p++));
x[i] |= (((ent32)(*p++)) << 8);
x[i] |= (((ent32)(*p++)) << 16);
x[i] |= (((ent32)(*p++)) << 24);
}
//hex(p, 64);
/* */
a = s0;
b = s1;
c = s2;
d = s3;
/* Round 1 */
FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x02441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[ 6], S34, 0x04881d05); /* 44 */
HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
/* */
s0 += a;
s1 += b;
s2 += c;
s3 += d;
}
p = sortie->ptr; /* 16 octets en hexa */
char hexa[16] = "0123456789abcdef";
/* */
*p++ = hexa[(s0 >> 4) & 0xf];
*p++ = hexa[(s0) & 0xf];
*p++ = hexa[(s0 >> 12) & 0xf];
*p++ = hexa[(s0 >> 8) & 0xf];
*p++ = hexa[(s0 >> 20) & 0xf];
*p++ = hexa[(s0 >> 16) & 0xf];
*p++ = hexa[(s0 >> 28) & 0xf];
*p++ = hexa[(s0 >> 24) & 0xf];
/* */
*p++ = hexa[(s1 >> 4) & 0xf];
*p++ = hexa[(s1) & 0xf];
*p++ = hexa[(s1 >> 12) & 0xf];
*p++ = hexa[(s1 >> 8) & 0xf];
*p++ = hexa[(s1 >> 20) & 0xf];
*p++ = hexa[(s1 >> 16) & 0xf];
*p++ = hexa[(s1 >> 28) & 0xf];
*p++ = hexa[(s1 >> 24) & 0xf];
/* */
*p++ = hexa[(s2 >> 4) & 0xf];
*p++ = hexa[(s2) & 0xf];
*p++ = hexa[(s2 >> 12) & 0xf];
*p++ = hexa[(s2 >> 8) & 0xf];
*p++ = hexa[(s2 >> 20) & 0xf];
*p++ = hexa[(s2 >> 16) & 0xf];
*p++ = hexa[(s2 >> 28) & 0xf];
*p++ = hexa[(s2 >> 24) & 0xf];
/* */
*p++ = hexa[(s3 >> 4) & 0xf];
*p++ = hexa[(s3) & 0xf];
*p++ = hexa[(s3 >> 12) & 0xf];
*p++ = hexa[(s3 >> 8) & 0xf];
*p++ = hexa[(s3 >> 20) & 0xf];
*p++ = hexa[(s3 >> 16) & 0xf];
*p++ = hexa[(s3 >> 28) & 0xf];
*p++ = hexa[(s3 >> 24) & 0xf];
/* */
dynSetLen(e, sortie, 32);
}
/* *********************************************************************************** */
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
@@ -333,7 +566,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -346,7 +579,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//*** code specifique ici
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
@@ -355,55 +588,76 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODETAT;
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
else if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
if(param1->type == VAR_NUMBER)
if(param1 == NULL)
exc = EX_MODETAT;
else if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "MD2", 3) == 0)
else if(modFnIs(e, "MD2", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD2(param1->mPtr, param1->lg, param2->mPtr);
encodageMD2(e, param1, param2);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "MD4", 3) == 0)
else if(modFnIs(e, "MD4", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD4(param1->mPtr, param1->lg, param2->mPtr);
encodageMD4(e, param1, param2);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD5", 3))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD5(e, param1, param2);
}
}
/* ----------------------------------------------------------------------------------------------- */
+76 -25
View File
@@ -27,31 +27,64 @@
#include "langage.h"
#include "var.h"
#include "hashtable.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
// =============== PRIVATE ========================================================================
static entry * calc_entry(char * val, var * varht)
{
/* fonctionne avec des noms de 24 octets max (val) */
/* algo de D. B e r n s t e i n */
ent64 hash = 5381;
/* optimiser en travaillant sur 3 qword ou 6 dword mais
pbm les petites chaines donneront des modules idem */
/* ent64 * p = (ent64 *)val;
hash += *p++;
hash = hash + (hash << 5) + *p++;
hash = hash + (hash << 5) + *p;*/
for(int iCle = 0; iCle < 24; iCle++)
if(val[iCle])
hash = hash + (hash<<5) + val[iCle]; /* hash*33 */
else
break; // stop au premier \0
ent64 hash;
/* algo de D. B e r n s t e i n / M u r m u r h a s h 6 4 */
/* autre algo */
if(0) {
ent64 * p = (ent64 *)val;
ent64 k = *p++;
ent64 m = 0xc6a4a7935bd1e995ull;
hash = 5381 ^ (24 * m);
//
k *= m;
k ^= k >> 47;
k *= m;
hash ^= k;
hash *= m;
k = *p++; /* */
k *= m;
k ^= k >> 47;
k *= m;
hash ^= k;
hash *= m;
k = *p; /* */
k *= m;
k ^= k >> 47;
k *= m;
hash ^= k;
hash *= m;
}
/* */
if(1) {
hash = 5381;
for(int iCle = 0; iCle < 24; iCle++)
if(val[iCle])
hash = hash + (hash<<5) + val[iCle]; /* hash*33 */
else
break; // stop au premier \0
}
return((entry *)(varht->ptr + (varht->separateur * (hash % varht->modulo))));
}
// =============== PUBLIC ========================================================================
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
{
/* READ renvoi le ptr sur la var (ne fait pas une copie de la var)
WRITE copie la var (si pas trouve ou trouve mais pointeurs differents)
@@ -153,7 +186,12 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
}
}
void hashtable_select(env * e, var * varht)
WAPIDECL var * hashtable_lastitemwritten(var * varht)
{
return ((entry *)varht->ptr)->pvar;
}
WAPIDECL void hashtable_select(env * e, var * varht)
{
/* les 4 variables necessaires seront mises dans le groupe 0, premiere entree (celle servant au chainage) */
/* dans la variable (content, inutilise) : */
@@ -169,7 +207,7 @@ void hashtable_select(env * e, var * varht)
pvar->ptr = (pointeur)(pentry+1); /* pentry */
}
int hashtable_next(env * e, var * varht, char * nom, var ** v)
WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v)
{
var * pvar;
entry * pentry;
@@ -208,7 +246,7 @@ int hashtable_next(env * e, var * varht, char * nom, var ** v)
return FALSE;
}
void hashtable_free_ovf(env *e, var * varht)
WAPIDECL void hashtable_free_ovf(env *e, var * varht)
{
/* libere les overflow de la hash table */
/* pour chaque entree, chainage avant puis liberation en revenant en arriere */
@@ -231,7 +269,7 @@ void hashtable_free_ovf(env *e, var * varht)
/* reste a liberer le bloc primaire de la hashtable */
}
void hashtable_clear(env * e, var * varht)
WAPIDECL void hashtable_clear(env * e, var * varht)
{
var * pvar;
int suivrepar = TRUE;
@@ -247,7 +285,7 @@ void hashtable_clear(env * e, var * varht)
hashtable_select(e, varht);
}
long hashtable_count(env *e, var * varht)
WAPIDECL long hashtable_count(env *e, var * varht)
{
long nb = 0;
var * pvar;
@@ -260,13 +298,13 @@ long hashtable_count(env *e, var * varht)
return nb;
}
void hashtable_printdebug(env * e, var * varht, int detail)
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
{
entry * pentry; /* pointe sur une entree */
entry * pchain; /* pointe sur la premiere du groupe, servant au chainage */
entry * pchain_first; /* premier bloc */
ent64 groupe; /* groupe en cours */
ent64 occ, tot; /* taille occupee, totale */
ent64 occ, tot, nb; /* taille occupee, totale, nb items */
char * ptrClass = NULL;
/* affiche le contenu d'une hashtable */
if(varht == NULL)
@@ -275,10 +313,18 @@ void hashtable_printdebug(env * e, var * varht, int detail)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
printf("hashtable modulo=%lld separateur=%lld (n=%lld)\n", varht->modulo, varht->separateur, varht->separateur/sizeof(entry));
if(e->demon)
{
dynPrintfInt64(e, "hashtable modulo=" PRINTF_MARK " separateur=", varht->modulo, 0);
dynPrintfInt64(e, PRINTF_MARK " (n=", varht->separateur, 0);
dynPrintfInt64(e, PRINTF_MARK ")\n", varht->separateur/sizeof(entry), 0);
}
else
printf("hashtable modulo=%lld separateur=%lld (n=%lld)\n", varht->modulo, varht->separateur, varht->separateur/sizeof(entry));
/* */
occ = 0;
tot = 0;
nb = 0;
pchain = (entry *)varht->ptr;
for(groupe = 0; groupe < varht->modulo; groupe++)
{
@@ -312,10 +358,11 @@ void hashtable_printdebug(env * e, var * varht, int detail)
else
printf("%c", e->var_car[pentry->content.type % 10]);
/* */
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, "_class", 6) == 0 && ! ptrClass)
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, GUV_CLASS, 6) == 0 && ! ptrClass)
ptrClass = pentry->content.mPtr;
/* */
occ += sizeof(entry);
nb++;
}
pentry++;
}
@@ -325,8 +372,12 @@ void hashtable_printdebug(env * e, var * varht, int detail)
pchain = (entry *)((ent64)pchain_first + varht->separateur);
}
if(ptrClass)
printf("_class : %s\n", ptrClass);
printf("taille totale=%lld, occupee=%lld (taux %lld%%)\n", tot, occ, occ * 100 / tot);
{
dynLet(e, &e->tmp_dynamic, ptrClass, DYN_LGNONE);
dynReplace(e, &e->tmp_dynamic, cFM, ':');
printf("%s %s\n", GUV_CLASS, e->tmp_dynamic.mPtr);
}
printf("taille totale=%lld, occupee=%lld (taux %lld%%), nb item=%lld\n", tot, occ, occ * 100 / tot, nb);
}
/* ********************************************** */
+10 -7
View File
@@ -23,14 +23,17 @@
#ifndef HASHTABLE_H
#define HASHTABLE_H
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
void hashtable_select(env * e, var * varht);
int hashtable_next(env * e, var * varht, char * nom, var ** v);
void hashtable_free_ovf(env *e, var * varht);
void hashtable_clear(env *e, var * varht);
long hashtable_count(env *e, var * varht);
#include "apidecl.h"
void hashtable_printdebug(env * e, var * varht, int detail);
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
WAPIDECL void hashtable_select(env * e, var * varht);
WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v);
WAPIDECL void hashtable_free_ovf(env *e, var * varht);
WAPIDECL void hashtable_clear(env *e, var * varht);
WAPIDECL long hashtable_count(env *e, var * varht);
WAPIDECL var * hashtable_lastitemwritten(var * varht);
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail);
/* ********************************************** */
#endif
+192
View File
@@ -0,0 +1,192 @@
void instr_unassemble(env * e, pointeur debutBin, ent64 nolig)
{
char * l = libInstr + e->instr * 4;
//
if(e->fin - debutBin > 9999)
printf("[%d:%08lld-%08lld-%08lld ex %08lld]", e->bin_indice, (ent64)(e->debut - debutBin), (ent64)(e->si - 1 - debutBin), (ent64)(e->fin - debutBin), (ent64)(e->si_except - debutBin));
else
printf("[%d:%04lld-%04lld-%04lld ex %04lld]", e->bin_indice, (ent64)(e->debut - debutBin), (ent64)(e->si - 1 - debutBin), (ent64)(e->fin - debutBin), (ent64)(e->si_except - debutBin));
//
printf(" line %06lld ex-ex %04lld > %c%c%c%c ", nolig, e->except_ex, *l, *(l+1), *(l+2), *(l+3));
//
ent64s d8;
int d3;
octet d1;
pointeur p = e->si;
//
switch(e->instr)
{
/* 2 bytes w opcode (instr d1) */
case IN_VERS:
case IN_PART:
case IN_PREC:
d1 = lire8(p);
printf("%d", d1);
break;
/* special 2 bytes w opcode */
case IN_COMP:
d1 = lire8(p);
if(d1 < CMP_EQ || d1 > CMP_FOR)
printf("??? (%d)", d1);
else
{
l = libComp + d1 * 3 - 3;
printf("%c%c%c", *l, *(l+1), *(l+2));
}
break;
case IN_PSHA:
dynLet(e, &e->tmp_dynamic, VARSYS, DYN_LGNONE);
d1 = lire8(p);
d3 = dynLocateSz(e, &e->tmp_dynamic, Int32ToSz(d1, FALSE, 0), ',', 2, ';');
if(d3 > 0)
{
d3 = dynExtractPos(e, &e->tmp_dynamic, 1, d3, ';', ',');
if(d3 > 0)
printf("%.*s", d3, &e->tmp_dynamic.mPtr[e->tmp_dynamic.mInternal]);
}
if(d3 <= 0)
printf("?? (%d)\n", d1);
break;
/* 2+lg bytes w opcode (instr lg valeur) */
case IN_DECL:
case IN_CALL:
case IN_PARM:
case IN_MODL:
case IN_PVAR:
case IN_PVAH:
case IN_DSET:
case IN_DSTO:
case IN_VLET:
case IN_DCAT:
case IN_NLET:
case IN_INCL:
case IN_PNAM:
case IN_CLIB:
case IN_PVAI:
case IN_CPSH:
case IN_PHDE:
case IN_PIDE:
case IN_PHDH:
case IN_PIDH:
case IN_PHDO:
case IN_PIDO:
case IN_PHDN:
case IN_PIDN:
case IN_PHDV:
case IN_PIDV:
case IN_PVHD:
case IN_PVID:
case IN_DEXH:
case IN_DEXI:
case IN_DESH:
case IN_DESI:
case IN_DEZH:
case IN_DEZI:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* 3+lg bytes w opcode (instr lg valeur) */
case IN_DCMP:
d1 = lire8(p++);
if(d1 < CMP_EQ || d1 > CMP_NOT)
printf("??? (%d) ", d1);
else
{
l = libComp + d1 * 3 - 3;
printf("%c%c%c ", *l, *(l+1), *(l+2));
}
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* 5+lg bytes w opcode (instr lg valeur) */
case IN_SUBR:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
d3 = lire24(p) + (e->si - 1 - debutBin);
printf(" %d", d3);
break;
case IN_PHDS:
case IN_PIDS:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
d3 = lire24(p);
printf(" %d", d3);
break;
/* 4 bytes w opcode (instr d3) */
case IN_JUMP:
case IN_JMPF:
case IN_JMPT:
d3 = lire24(e->si) + (e->debut - debutBin);
printf("%d", d3);
break;
case IN_BEXC:
d3 = lire24(e->si) + (e->si - 1 - debutBin);
printf("%d", d3);
break;
case IN_SRCL:
case IN_THRW:
d3 = lire24(e->si);
printf("%d", d3);
break;
/* 9 bytes w opcode */
case IN_PSHC:
d8 = lire64(p);
printf("%lld\n", d8);
break;
/* 3+lg1+lg2 bytes w opcode */
case IN_CLAS:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
printf(":");
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* 4+d3 bytes w opcode */
case IN_SDBG:
d3 = *p++;
if(d3 > 0)
for( ;d3;d3--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* one byte w opcode (and unknown opcode...) */
default:
break;
}
printf("\n");
}
+31 -5
View File
@@ -27,6 +27,7 @@
/* ************************************ */
/* AJOUT D'UNE INSTRUCTION
- instr.h : ci-dessous, 2 constantes + ajout a libInstr
- instr.c : ajout constante, si besoin, dans instr_unassemble
- langage.c : ajout dans le tableau de function instr + dans le commentaire en dessous,
ajouter la function instr_xxx
- assembler.c : ajout switch de la function assembler,
@@ -38,7 +39,7 @@
char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW" "PART" "RETN"
"CALL" "PARM" "SUBR" "COMP" "JMPF" "JMPT" "ADDN" "SBCN" "MULN" "DIVN"
"INTE" "FRAC" "NEGN" "ABSN" "MODL" "PSHC" "PSHV" "POPV" "PVAR" "PVAH"
"WRIT" "WRLN" "DSET" "DEXV" "DCMP" "DSTO" "VLET" "DCAT" "DTON" "NTOD"
"WRIT" "WRLN" "DSET" "DEXV" "DCMP" "DSTO" "LETV" "DCAT" "DTON" "NTOD"
"DELE" "HLET" "CLAS" "NLET" "INCL" "PNAM" "PSH0" "PSH1" "PSH2" "PSH3"
"PSH4" "PSH5" "PSH6" "PSH7" "PSH8" "PSH9" "PSHA" "PROG" "BACK" "CLIB"
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPSH" "RETT"
@@ -46,8 +47,8 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"PIDS" "TYPE" "ROUN" "LENG" "COUN" "DCOF" "FIEL" "INDX" "SRCH" "CHNG"
"FMTA" "INSE" "REMV" "TONU" "TOST" "CCAT" "SSTR" "SSEP" "FLDF" "FLDS" /* 0-99 */
"DCOS" "FMTT" "FMTS" "SCHS" "INSS" "REMS" "DEXH" "DEXI" "PREC" "DESV"
"DESH" "DESI" "DEZV" "DEZH" "DEZI" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" /* 110-119 */
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"DESH" "DESI" "DEZV" "DEZH" "DEZI" "SDBG" "PHDN" "PIDN" "SADV" "VLET" /* 110-119 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "SSRC" "SSCS" "xxxx" "xxxx" "xxxx" /* 126 */
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
@@ -62,6 +63,7 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" /* 200-249 */
"xxxx" "LIBR" "ENDL" "TEST" "ENDS" "ENDP"};
char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "FOR"};
#define IS_VERS "\x00"
#define IN_VERS 0
@@ -138,8 +140,8 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
#define IN_DCMP 34
#define IS_DSTO "\x23"
#define IN_DSTO 35
#define IS_VLET "\x24"
#define IN_VLET 36
#define IS_LETV "\x24"
#define IN_LETV 36
#define IS_DCAT "\x25"
#define IN_DCAT 37
#define IS_DTON "\x26"
@@ -304,6 +306,30 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
#define IN_DEZH 113
#define IS_DEZI "\x72"
#define IN_DEZI 114
#define IS_SDBG "\x73"
#define IN_SDBG 115
#define IS_PHDN "\x74"
#define IN_PHDN 116
#define IS_PIDN "\x75"
#define IN_PIDN 117
#define IS_SADV "\x76"
#define IN_SADV 118
#define IS_VLET "\x77"
#define IN_VLET 119
#define IS_PHDV "\x78"
#define IN_PHDV 120
#define IS_PIDV "\x79"
#define IN_PIDV 121
#define IS_HCOU "\x7A"
#define IN_HCOU 122
#define IS_PVHD "\x7B"
#define IN_PVHD 123
#define IS_PVID "\x7C"
#define IN_PVID 124
#define IS_SSRC "\x7D"
#define IN_SSRC 125
#define IS_SSCS "\x7E"
#define IN_SSCS 126
#define IS_LIBR "\xFB"
#define IN_LIBR 251
+44 -27
View File
@@ -1,3 +1,25 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
@@ -29,39 +51,34 @@ typedef struct
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMODJSON_MEM 106
#define EXMODJSON_DECODE_INCORRECT_CHAR 101
#define EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED 102
#define EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED 103
#define EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED 104
#define EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER 105
#define EXMODJSON_DECODE_UNTERMINATED_STRING 107
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT 108
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY 109
#define EXMODJSON_DECODE_UNEXPECTED_KEY 110
#define EXMODJSON_DECODE_UNEXPECTED_VALUE 111
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT 112
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT 113
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY 114
#define EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON 115
enum {
EXMODJSON_MEM = 106,
EXMODJSON_DECODE_INCORRECT_CHAR = 101,
EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED = 102,
EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED = 103,
EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED = 104,
EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER = 105,
EXMODJSON_DECODE_UNTERMINATED_STRING = 107,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT = 108,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY = 109,
EXMODJSON_DECODE_UNEXPECTED_KEY = 110,
EXMODJSON_DECODE_UNEXPECTED_VALUE = 111,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT = 112,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT = 113,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY = 114,
EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON = 115
};
/*
Le decodage a besoin de mEncodeCle mEncodeValeur et la position de l'erreur si erreur (3 parametres ; en entree la position le flag "NoDQuote"). L'erreur est le code retour.
L'encodage a besoin de mEncode, mId, flag NoDQuote (3 parametres)
*/
int jsonInit(env * e, modContextJson * ctx);
int jsonEnd(env * e, modContextJson * ctx);
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
typedef struct {
var * KeyList, * CurrentKey, * Name, * Value, * DecodeCle, * DecodeValue; // Dynamic
var * KeyField, * KeyItem, * KeyCount, * ItemCount, * Id, * Parent, * IdKey, * ParentKey, * ValuePresent, * Begin; // Number
// output: Name Value IdKey IdParent ValuePresent
} treefetch; // contenu de la var hashtable passee en param
int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonInit(env * e, modContextJson * ctx);
WAPIDECL int jsonEnd(env * e, modContextJson * ctx);
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
/*
+12 -13
View File
@@ -43,13 +43,12 @@ static int setError(modEtat * p, int err)
return err == OK ? OK : EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -73,7 +72,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -87,7 +86,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
@@ -95,7 +94,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -110,7 +109,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -126,7 +125,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "decode", 6) == 0)
else if(modFnIs(e, "decode", 6))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
@@ -141,7 +140,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "print", 5) == 0)
else if(modFnIs(e, "print", 5))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
@@ -154,14 +153,14 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, param1, param2, param3));
}
}
else if(strncmp(e->fn, "treeFetch", 9) == 0)
else if(modFnIs(e, "treeFetch", 9))
{
if(param1 == NULL)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else
{
/* param1 must be a hash table (input) */
if(param1->type != VAR_HASHTABLE)
if(param1->type != VAR_HASHTABLE || param2->type != VAR_NUMBER)
exc = EX_MODPARAM; // bad type of parameter 1
else
exc = setError(p_etat, jsonTreeFetch(e, &p_etat->jsonCtx, param1, param2, param3));
+177 -61
View File
@@ -1,3 +1,25 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -7,8 +29,16 @@
#include "var.h"
#include "hashtable.h"
#define LF 10
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ------------------------------------------ */
#define CAR_DQUOTE '"'
#define CAR_MARQUE_CLE ':'
#define CAR_DEBUT_OBJET '{'
@@ -25,23 +55,27 @@
#define STR_FIN_TABLEAU "]"
#define STR_SUIVANT ","
#define DEBUT_FICHIER 0
#define VALEUR_CHAINE 1
#define VALEUR_NOMBRE 2
#define VALEUR_CLE 3
#define DEBUT_OBJET 4
#define FIN_OBJET 5
#define DEBUT_TABLEAU 6
#define FIN_TABLEAU 7
#define SUIVANT 8
#define FIN_FICHIER 9
enum {
DEBUT_FICHIER = 0,
VALEUR_CHAINE = 1,
VALEUR_NOMBRE = 2,
VALEUR_CLE = 3,
DEBUT_OBJET = 4,
FIN_OBJET = 5,
DEBUT_TABLEAU = 6,
FIN_TABLEAU = 7,
SUIVANT = 8,
FIN_FICHIER = 9,
#define ENCODE_OK 1
#define ENCODE_ERREUR 0
ENCODE_OK = 1,
ENCODE_ERREUR = 0,
LF = 10
};
/* =================================================================================== */
/* --------- JSON C --------- */
/* --------- PRIVATE --------- */
static void ConcatValue(env * e, modContextJson * ctx, char c)
{
char car[2];
@@ -484,52 +518,83 @@ static int MakePrintable(env * e, modContextJson * ctx, var * DecodeBrut, var *
return OK;
}
/* NOT USED
static void InitTreeFetch()
{
GetNextTreeFetch(NULL, NULL, NULL, NULL, NULL);
}
*/
typedef struct {
var * KeyList, * CurrentKey, * Name, * Value, * DecodeCle, * DecodeValue; // Dynamic
var * KeyField, * KeyItem, * KeyCount, * ItemCount, * Id, * Parent, * IdKey, * ParentKey, * ValuePresent; // Number
// output: Name Value IdKey ParentKey ValuePresent
} treefetch; // contenu de la var hashtable passee en param
/*
static int GetNextTreeFetch(env * e, modContextJson * ctx, long * parentKey, long * idKey, Dynamic * name, Dynamic * value, int * valuePresent)
static int GetNextTreeFetch(env * e, treefetch * tree)
{
static Dynamic KeyList, CurrentKey; // hash entree
static long KeyField, KeyItem, KeyCount, ItemCount, id, parent; // hash entree
char ArrayMark = '#';
//
if(parentKey == NULL && idKey == NULL && name == NULL && value == NULL && valuePresent == NULL)
{
// InitTreeFetch
KeyList.DeleteAllContent();
KeyField = 1; // current field in mDecodeCle
KeyItem = 1; // current part of path of current field
mDecodeCle.SetSubFieldDelimiter(cSVM);
KeyCount = mDecodeCle.CountField();
ItemCount = mDecodeCle.CountSubField(KeyField);
id = 1;
parent = 0;
return true;
}
if(parentKey == nullptr || idKey == nullptr || name == nullptr || value == nullptr || valuePresent == nullptr)
return false; // security
//
if(KeyField == 0)
return false; // false = fini
//
if(tree->KeyField->num == 0)
return FALSE; // false = fini
// check here if empty json
if(KeyCount == 0 && ItemCount == 0)
if(tree->KeyCount->num == 0 && tree->ItemCount->num == 0)
{
// single value json
name->SetAs("#");
mDecodeValeur.ExtractField(1, *value, 1);
*parentKey = parent;
*idKey = id;
*valuePresent = true;
KeyField = 0;
return true;
dynLet(e, tree->Name, "#", 1);
dynField(e, tree->DecodeValue, tree->Value, 1, DYN_NONE, cVM, cSVM, 1);
tree->ParentKey->num = tree->Parent->num;
tree->IdKey->num = tree->Id->num;
tree->ValuePresent->num = NUM_UN;
tree->KeyField->num = 0;
return TRUE;
}
//
for(long pos;;)
{
if(tree->KeyItem->num == tree->ItemCount->num)
{
// value found
tree->ParentKey->num = tree->Parent->num;
tree->IdKey->num = tree->Id->num;
dynField(e, tree->DecodeCle, tree->Name, tree->KeyField->num, tree->KeyItem->num, cVM, cSVM, 1);
dynReplace(e, tree->Name, cTM, ArrayMark);
dynField(e, tree->DecodeValue, tree->Value, tree->KeyField->num, DYN_NONE, cVM, DYN_NONE, 1);
tree->ValuePresent->num = TRUE; // means send a value
// prepare next call
if(tree->KeyField->num >= tree->KeyCount->num)
tree->KeyField->num = 0;
else
{
tree->Id->num++;
tree->Parent->num = 0;
tree->KeyField->num++;
tree->KeyItem->num = 1;
tree->ItemCount->num = dynDcount(e, tree->DecodeCle, cSVM, tree->KeyField->num, cVM);
}
return TRUE;
}
dynField(e, tree->DecodeCle, tree->CurrentKey, tree->KeyField->num, 1, cVM, cSVM, tree->KeyItem->num);
pos = dynLocateSz(e, tree->KeyList, tree->CurrentKey->mPtr, cVM, 1, cFM);
if(pos < 1)
{
// new path
dynIns(e, tree->KeyList, 1, 1, tree->CurrentKey, cFM, cVM);
dynInsNumber(e, tree->KeyList, 2, 1, tree->Id->num, cFM, cVM);
// part of path found
tree->ParentKey->num = tree->Parent->num;
tree->IdKey->num = tree->Id->num;
dynField(e, tree->DecodeCle, tree->Name, tree->KeyField->num, tree->KeyItem->num, cVM, cSVM, 1);
dynReplace(e, tree->Name, cTM, ArrayMark);
tree->ValuePresent->num = NUM_ZERO; // means no value here (part of path)
// prepare next call
tree->Parent->num = tree->Id->num++;
tree->KeyItem->num++;
//
return TRUE;
}
// loop to next part of path
dynExtractSubField(e, tree->KeyList, 2, pos, tree->Parent);
tree->KeyItem->num++;
}
//
return TRUE; //ok, but should never reach this point...
}
/*
for(long pos;;)
{
if(KeyItem == ItemCount)
@@ -577,12 +642,10 @@ static int GetNextTreeFetch(env * e, modContextJson * ctx, long * parentKey, lon
KeyList.ExtractSubField(2, pos, parent);
KeyItem++;
}
//
return true; //ok, but should never reach this point...
}*/
*/
/* =================== PUBLIC ========================== */
int jsonInit(env * e, modContextJson * ctx)
WAPIDECL int jsonInit(env * e, modContextJson * ctx)
{
int cr = OK;
//cr += dynInit(e, &ctx->mKeyList, DYN_LGMIN);
@@ -607,7 +670,7 @@ int jsonInit(env * e, modContextJson * ctx)
return (cr == OK ? OK : EXMODJSON_MEM);
}
int jsonEnd(env * e, modContextJson * ctx)
WAPIDECL int jsonEnd(env * e, modContextJson * ctx)
{
//dynFree(e, &ctx->mKeyList);
//dynFree(e, &ctx->mCurrentKey);
@@ -619,23 +682,76 @@ int jsonEnd(env * e, modContextJson * ctx)
return OK;
}
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
{
return Decode(e, ctx, param1->mPtr, param2, param3);
}
int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
{
char value[4] = " : \0", path = '/', index = '@';
//
return MakePrintable(e, ctx, param1, param2, param3, path, index, value);
}
int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
{
// KeyList, CurrentKey, Name, Value, DecodeCle, DecodeValue; // Dynamic
// KeyField, KeyItem, KeyCount, ItemCount, Id, Parent, IdKey, ParentKey, ValuePresent, Begin; // Number
treefetch tree;
// KeyField, KeyItem, KeyCount, ItemCount, Id, Parent, IdKey, ParentKey, ValuePresent; // Number
treefetch tree; // contexte specifique a chaque appel
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeCle"), &tree.DecodeCle);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeValue"), &tree.DecodeValue);
if(tree.DecodeCle == NULL || tree.DecodeValue == NULL)
{
param2->num = NUM_UN;
return OK; // TODO erreur
}
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
if(tree.KeyList == NULL)
{
// init vars
var * v = &e->int_dynamic;
dynSetLen(e, &e->int_dynamic, 0);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyList"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "CurrentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Name"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Value"), &v);
v = &e->int_number;
v->num = 1;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyField"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyItem"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Id"), &v);
v->num = 0;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Parent"), &v);
v->num = dynDcount(e, tree.DecodeCle, cVM, DYN_NONE, DYN_NONE);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyCount"), &v);
v->num = dynDcount(e, tree.DecodeCle, cSVM, 1, cVM);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ItemCount"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "IdKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ParentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ValuePresent"), &v);
}
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CurrentKey"), &tree.CurrentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Name"), &tree.Name);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Value"), &tree.Value);
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyField"), &tree.KeyField);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyItem"), &tree.KeyItem);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyCount"), &tree.KeyCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ItemCount"), &tree.ItemCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Id"), &tree.Id);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Parent"), &tree.Parent);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "IdKey"), &tree.IdKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ParentKey"), &tree.ParentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ValuePresent"), &tree.ValuePresent);
/* */
//hashtable_printdebug(e, param1, 1);
if(GetNextTreeFetch(e, &tree)) // TRUE = pas fini
param2->num = NUM_ZERO; // var <fin>
else
param2->num = NUM_UN;
return OK;
}
+1591 -1763
View File
File diff suppressed because it is too large. Load diff
+144 -83
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -23,16 +23,20 @@
#ifndef LANGAGE_H
#define LANGAGE_H
#define VERSION 1 // version "max" gere du pcode => version du "langage"
enum {
VERSION = 1 // version "max" gere du pcode => version du "langage"
};
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define W_LITTLE_ENDIAN 1
#define W_BIG_ENDIAN 0
#define W_DEFAULT_ENDIAN 2 // celle de la plateforme d'execution
enum {
W_LITTLE_ENDIAN = 1,
W_BIG_ENDIAN = 0,
W_DEFAULT_ENDIAN = 2 // celle de la plateforme d'execution
};
typedef unsigned char octet;
typedef octet * pointeur; /* et pas "void *" ... */
@@ -44,7 +48,11 @@ typedef int ent32s;
typedef long long ent64s;
typedef unsigned short ent16;
#ifndef UNIX
typedef ent64s ent128s; // sous windows, pas de __int128 : TODO a changer pour des calculs corrects
#else
typedef __int128 ent128s; // temporaire pour les calculs intermediaires (multiplication)
#endif
#define NUM_MIN -999999999999999999ll
#define NUM_MAX 999999999999999999ll
@@ -69,31 +77,36 @@ typedef ent64s number; /* 8 octets signes, virgule fixe */
/* les variables ne sont pas typees : elles peuvent changer de type au fur et a mesure des affectations */
/* type 0 indique que l'emplacement n'a pas ete utilise encore : place disponible */
#define VAR_NULL 1 /* variable declaree mais pas encore affectee d'une valeur */
#define VAR_NUMBER 2 /* et @number */
#define VAR_SUBROUTINE 3
#define VAR_PARAM 4 /* adresse de la "vraie" variable, 1 seul niveau d'indirection, travail toujours sur la var "pointee" */
#define VAR_DYNAMIC 5 /* et @string */
#define VAR_HASHTABLE 6
#define VAR_OBJECT 7 /* idem hashtable mais en objet : seule diff. element "_class" cree dans la table (interne) */
#define VAR_BUFFER 8 /* usage interne : pile calcul + pile appel sub (autre ? buffer circulaire ptr read/write) */
#define VAR_NB 8
#define VAR_EMPTY 0 /* retour @empty */
enum {
VAR_NULL = 1, /* variable declaree mais pas encore affectee d'une valeur */
VAR_NUMBER = 2, /* et @number */
VAR_SUBROUTINE = 3,
VAR_PARAM = 4, /* adresse de la "vraie" variable, 1 seul niveau d'indirection, travail toujours sur la var "pointee" */
VAR_DYNAMIC = 5, /* et @string */
VAR_HASHTABLE = 6,
VAR_OBJECT = 7, /* idem hashtable mais en objet : seule diff. element "_class" cree dans la table (interne) */
VAR_BUFFER = 8, /* usage interne : pile calcul + pile appel sub (autre ? buffer circulaire ptr read/write) */
VAR_NB = 8,
VAR_EMPTY = 0, /* retour @empty fonction type(expr) */
#define VAR_UNDECLARED -1
VAR_UNDECLARED = 0, /* cas de retour si pas de var dans "typeof var1.var2.var3" */
#define CP_WIN1252 1252
#define CP_8859_1 28591
#define CP_8859_15 28605
#define CP_UTF8 65001
WCP_WIN1252 = 1252,
WCP_8859_1 = 28591,
WCP_8859_15 = 28605,
WCP_UTF8 = 65001,
WCP_DEFAULT = WCP_WIN1252 // UTF8 ??
};
typedef struct {
union {
ent64 type; /* type defini ci-dessus */
//union {
ent16 type; /* type defini ci-dessus (au lieu de ent64) */
//pointeur local; /* pour memo _stack */
ent16 typv[4]; /* permet de gerer des options par type : code page pour dynamic, unite/devise pour number, fuseau si number/date etc. */
ent16 codePage; /* pour dynamic */
ent16 typv[2]; /* permet de gerer des options par type : unite/devise pour number, fuseau si number/date etc. */
/* typv[0] = type; typv[1] = code page/unite/fuseau typv[2] typv[3] usage futur (langue, pays) */
};
//};
union {
number num; /* si type = 1 VAR_NUMBER */
pointeur ptr; /* si type = 2 a 8 : pointeur vers les donnees variables / variable si "PARAM" / si->debut si SUBROUTINE / ptr si module */
@@ -156,9 +169,6 @@ typedef struct {
v->ptr v->ptr v->misc
*/
#define BUF_LGBLOC 8192 /* multiple de 32 sinon pile d'elements 8 et 16 octets KO */
#define BUF_LGWRITE_MAX 4000 /* doit etre au maxi BUF_LGBLOC - 3 */
typedef struct {
/* buffer servant de stack pour number et string */
number num; /* nombre si str == NULL */
@@ -181,61 +191,71 @@ typedef struct {
/* vrai buffer read = position a lire dans les donnees (a ajouter a ptr) ou prochaine position a ecrire (pile calcul et appel) */
/* vrai buffer write = position a ecrire dans les donnees (a ajouter a ptr) ; si READ=WRITE : vide ! ou utilise en interne si pile */
#define OID_MAX 9999999999999999ll /* pour que l'OID reste sur 16 chiffres : 16 neufs ici */
#define OID_MAX 999999999999999ll /* pour que l'OID reste sur 16 chiffres : 15 neufs ici, pour qu'un oid commence toujours par 0 ! */
#define OID_MIN 100ll /* demarrage a 100 pour eviter les nombres trop petits */
#define CLASS_BASE "Base" /* classe mere de toutes les classes */
#define MAX_PARAM 8 /* nb maxi de parametres d'une sub/methode */
enum {
BUF_LGMINBLOC = 16384, /* multiple de 32 sinon pile d'elements 8 et 16 octets KO, lgmax message = lg buffer / 32 (512 octets ici) */
MAX_PARAM = 8, /* nb maxi de parametres d'une sub/methode */
#define HASH_READ 1
#define HASH_DELETE 2
#define HASH_WRITE 3
HASH_READ = 1,
HASH_DELETE = 2,
HASH_WRITE = 3,
#define NOK -1 /* quand pas une exception */
NOK = -1 /* quand pas une exception */
};
//
// 000 a 999 : erreur systeme
// 1000 a 9999 : reserve aux modules systeme
// 1000 a 1099 : module "db"
//
#define OK 0
#define EX_DIV0 1 /* exceptions */
#define EX_MEM 2 /* memalloc ko */
#define EX_BUFOVF 3 /* depassement de capacite du buffer */
#define EX_IO 4 /* erreur d'entree/sortie (leture fichier...) */
#define EX_END 5 /* adresse du code hors prog/sub */
#define EX_LGNOM 6 /* lg nom variable incorrecte (de 1 a 24 inclus) */
#define EX_TYPVAR 7 /* type variable non attendu */
#define EX_NULLOCAL 8 /* hashtable locale null et pas dans le code "global" */
#define EX_NOVAR 9 /* nom de variable inconnu */
#define EX_MODOPEN 10 /* erreur ouverture module (dlopen) */
#define EX_MODDSYM 11 /* fonction execModule non trouvee dans le module (dsym) */
#define EX_NOSTACK 12 /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
#define EX_NAVAR 13 /* la variable n'est pas du bon type / not available */
#define EX_NOADVAR 14 /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
#define EX_NAVERS 15 /* version de pcode non prise en charge par le "compilateur" */
#define EX_MODNAME 16 /* le nom d'appel du module est incorrect */
#define EX_DYNERR 17 /* erreur dans la manipulation des chaines */
#define EX_MODFUNC 18 /* le code function du module est inconnu */
#define EX_MODPARAM 19 /* le parametre donne au module est incorrect */
#define EX_MODETAT 20 /* l'etat interne du module est incorrect */
#define EX_MODERR 21 /* erreur specifique au module */
#define EX_NOTNUM 22 /* erreur de conversion de chaine en number */
#define EX_NOCLASS 23 /* la classe n'a pas ete trouvee dans la hash globale */
#define EX_CMDLINE_ARG 24 /* erreur dans les parametres de la ligne de commande */
#define EX_PCODE 25 /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
#define EX_NOENVVAR 26 /* WBIN et/ou WSRC non defini en var d'envvironnement ou non passe en parametre de la ligne de commande */
#define EX_EXCEPTNUM 27 /* code except ne tient pas sur 8 bits : ko pour retour shell */
#define EX_BINVAR_KO 28 /* variable _bin de g non trouvee */
#define EX_ENVVAR_KO 29 /* variable _env de g non trouvee */
#define EX_BINADDRVAR_KO 30 /* variable _binaddr de g non trouvee */
#define EX_CREATEHASH 31 /* erreur de creation de hashtable (memoire) */
#define EX_FIELD_KO 32 /* erreur lors de dynField (memoire ou param incorrect) */
#define EX_SUBSTR_KO 33 /* erreur lors de dynSubstr (memoire ou param incorrect) */
#define EX_SEP_INCORRECT 34 /* separateurs incorrects dans setsep (0 interdit) */
#define EX_FORMAT_KO 35 /* erreur de parametre (type format ou longueur incorrects) */
#define EX_INSERT_KO 36 /* erreur de parametre ou memoire dans insert() */
#define EX_REMOVE_KO 37 /* erreur de parametre ou memoire dans remove() */
enum {
OK = 0,
EX_DIV0 = 1, /* exceptions */
EX_MEM = 2, /* memalloc ko */
EX_BUFOVF = 3, /* depassement de capacite du buffer */
EX_IO = 4,/* erreur d'entree/sortie (leture fichier...) */
EX_END = 5, /* adresse du code hors prog/sub */
EX_LGNOM = 6, /* lg nom variable incorrecte (de 1 a 24 inclus) */
EX_TYPVAR = 7, /* type variable non attendu */
EX_NULLOCAL = 8, /* hashtable locale null et pas dans le code "global" */
EX_NOVAR = 9, /* nom de variable inconnu */
EX_MODOPEN = 10, /* erreur ouverture module (dlopen) */
EX_MODDSYM = 11, /* fonction execModule non trouvee dans le module (dsym) */
EX_NOSTACK = 12, /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
EX_NAVAR = 13, /* la variable n'est pas du bon type / not available */
EX_NOADVAR = 14, /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
EX_NAVERS = 15, /* version de pcode non prise en charge par le "compilateur" */
EX_MODNAME = 16, /* le nom d'appel du module est incorrect */
EX_DYNERR = 17, /* erreur dans la manipulation des chaines */
EX_MODFUNC = 18, /* le code function du module est inconnu */
EX_MODPARAM = 19, /* le parametre donne au module est incorrect */
EX_MODETAT = 20, /* l'etat interne du module est incorrect */
EX_MODERR = 21, /* erreur specifique au module */
EX_NOTNUM = 22, /* erreur de conversion de chaine en number */
EX_NOCLASS = 23, /* la classe n'a pas ete trouvee dans la hash globale */
EX_CMDLINE_ARG = 24, /* erreur dans les parametres de la ligne de commande */
EX_PCODE = 25, /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
EX_NOENVVAR = 26, /* WBIN et/ou WSRC non defini en var d'environnement ou non passe en parametre de la ligne de commande */
EX_EXCEPTNUM = 27, /* code except ne tient pas sur 8 bits : ko pour retour shell */
EX_BINVAR_KO = 28, /* variable _bin de g non trouvee */
EX_ENVVAR_KO = 29, /* variable _env de g non trouvee */
EX_BINADDRVAR_KO = 30, /* variable _binaddr de g non trouvee */
EX_CREATEHASH = 31, /* erreur de creation de hashtable (memoire) */
EX_FIELD_KO = 32, /* erreur lors de dynField (memoire ou param incorrect) */
EX_SUBSTR_KO = 33, /* erreur lors de dynSubstr (memoire ou param incorrect) */
EX_SEP_INCORRECT = 34, /* separateurs incorrects dans setsep (0 interdit) */
EX_FORMAT_KO = 35, /* erreur de parametre (type format ou longueur incorrects) */
EX_INSERT_KO = 36, /* erreur de parametre ou memoire dans insert() */
EX_REMOVE_KO = 37, /* erreur de parametre ou memoire dans remove() */
EX_CHILD_FORK = 38, /* erreur de fork sur nouveau process */
EX_CHILD_EXEC = 39, /* erreur execution nouveau process */
EX_ZERO_FOR_INCR = 40, /* erreur increment a zero dans une boucle foreach numerique */
EX_SORTEDSEARCH_KO = 41, /* erreur de parametre (type de tri incorrect) */
EXNB = 41 /* MEMO !!!! */
};
typedef struct {
/* environnement global */
@@ -250,8 +270,9 @@ typedef struct {
octet tmp_cpt; /* nb de var tmp Dynamic, ne pas sauvegarder car dans la hash globale */
octet tmp_free; /* numero de var tmp Dynamic dispo ; si > tmp_cpt, a creer dans la hash globale */
//
//var tblptr; /* contient les pointeurs sur les vars de type SUB/PARAM/OBJET, pour les rendre VAR_NULL si le ptr est libere */
var varptrtbl; /* contient les pointeurs sur les vars de type SUB/PARAM/OBJET, pour les rendre VAR_NULL si le ptr est libere */
//
var tmp_dynamic; /* comme son nom l'indique... doit etre utilise localement et sur une portee tres courte ; pas d'utilisation inter instruction */
var int_number; /* variable number interne servant aux conversions */
var int_dynamic; /* variable dynamic interne servant aux conversions */
var int_hash; /* variable interne servant a la creation de classe/objet */
@@ -259,6 +280,9 @@ typedef struct {
var v; /* variable servant en interne */
var * ad_var; /* permet de recuperer l'adresse d'une var entre 2 instructions */
var * ad_var_hash; /* dans les enchainements PVAR/PVAH-PVAI, donne l'adresse de la hash possédant la "derniere" variable */
var * ad_var_obj; /* dans une affectation let ou do sub, donne l'objet concerne si objet, pour lire les membres (hors sub) -> pour creer this */
var * ad_var_class; /* donne l'objet de la classe mere de l'objet courant, objet Base si objet de classe Base */
var * ad_var_sav; /* pour memoriser ad_var sur une affectation simple let a.b = c.d, instruction SADV / VLET / PHDV / PIDV */
/* */
ent64 exception; /* exception courante (di) ; 0 ok, si # 0, levee d'une exception et saut au code qui le traite, 0 a chaque debut de fonction */
ent64 except_ex; /* dans bloc except, code erreur ayant genere l'exception ; a mettre a 0 a chaque debut de methode sauf si appel depuis le bloc except ! */
@@ -275,6 +299,8 @@ typedef struct {
var debugreglelex;
var debugcmd;
var debugvalex;
var printf;
void * debugCtxShm; /* pour le debug des process phantom */
/* */
octet bin_comp; /* indique si les binaires lus sont compresses (1) et si oui, avec une cle (2), 0 RAS */
octet demon; /* 1 si prog lance en demon, 0 sinon (lu par @demon) */
@@ -289,11 +315,17 @@ typedef struct {
char sep_field, sep_subfield; /* pour dynamic */
/* */
int endianess; /* pour detection automatique de l'endianess de la plateforme d'execution */
int use_signal; /* 1 si w gere et traite les signaux, 0 sinon (mode plugin : signaux geres par programme maitre) */
/* */
int level; /* niveau d'imvrication des appels do/call ; prog principal = level 1 */
/* */
int bin_indice; /* position dans _bin du binaire en cours d'exec ( _bin<2, bin_indice> ) */
/* */
pointeur debut,fin; /* position en memoire de la fonction, fin est toujours l'instruction END ou ENDS */
pointeur si; /* position dans le source, inclus entre debut et fin inclus */
pointeur si_except; /* position dans le source du code traitant les exceptions (apres instruction EXC) */
pointeur debutProg, finProg; // debut:fin du prog principal (= toute la zone memoire du prog)
/* */
pointeur binaddr; /* permet de lire les adresses binaires en mode Trace */
/* */
ent64 mem_numb; /* nombre de blocs memoire alloues */
ent64 mem_size; /* taille des bloc memoire alloues */
@@ -318,18 +350,47 @@ typedef struct {
char var_car[VAR_NB + 1]; /* lettre caracteristique de chaque type (printdebug) */
} env;
#define CMP_EQ 1
#define CMP_NE 2
#define CMP_LT 3
#define CMP_GT 4
#define CMP_LE 5
#define CMP_GE 6
enum {
CMP_EQ = 1,
CMP_NE = 2,
CMP_LT = 3,
CMP_GT = 4,
CMP_LE = 5,
CMP_GE = 6,
CMP_AND = 7,
CMP_OR = 8,
CMP_NOT = 9,
CMP_FOR = 10
};
#define CMP_AND 7
#define CMP_OR 8
#define CMP_NOT 9
enum {
FORMAT_TRIM = 1,
FORMAT_LEFT = 2,
FORMAT_RIGHT = 3,
FORMAT_CENTER = 4,
FORMAT_SURROUND = 5
};
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@forcount,@kill,@fork,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@number,@dynamic,@empty,@trim,@left,@right,@center,@surround;1,2,3,4,5,6,7,8,10,11,12,13,14,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,40,41,42,50,51,52,53,54"
enum {
SORTEDSEARCH_NONE = 0,
SORTEDSEARCH_ASC = 1, // = DYN_SORT_ASC
SORTEDSEARCH_DESC = 2 // = DYN_SORT_DESC
};
#define GUV_CLASS "_class"
#define GUV_BINADDR "_binaddr"
#define GUV_LOCAL "_local"
#define GUV_ENV "_env"
#define GUV_ARG "_arg"
#define GUV_WARGV "_wargv"
#define GUV_ARGBACK "_argback"
#define GUV_SRCDBG "_srcdbg"
#define GUV_PROG "_prog"
#define GUV_STACK "_stack"
#define GUV_BIN "_bin"
#define GUV_WDIR "_wdir"
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@level,@kill,@oid,@prog,@exceptstr,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@number,@dynamic,@empty,@trim,@left,@right,@center,@surround,@asc,@desc;1,2,3,4,5,6,7,8,10,11,12,13,14,15,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,40,41,42,50,51,52,53,54,55,56"
#include "global.h"
+294 -32
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -47,42 +47,253 @@ reste: (1,1,#00-#FF) ;11; 1,1,00-FF
[] est remplace par () car cela revient au meme !
*/
long regles_lex(env * e, Dynamic * r)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
static struct {
long blanc, nomregle, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} rlex;
static long rg_lex(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
dynLet(e, r, "", 0);
dynConcatSz(e, r, "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11\n", DYN_LGNONE);
//printf("%s", r->mPtr);
dynConcatSz(e, r, "1,-1,20:09\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,28\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,29\n", DYN_LGNONE);
dynConcatSz(e, r, "1,9,30-39;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2A;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,3B;0,-1,09-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2D\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,23;2,2,30-39:41-46\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,21-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,00-FF", DYN_LGNONE);
return DYN_OK;
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, 10);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, 10, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
//
long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
WAPIDECL void init_reg_lex(env * e, Dynamic * regles, Dynamic * tmp)
{
long cr;
rlex.blanc = rg_lex(e, regles, "blanc", tmp); // 1
rlex.nomregle = rg_lex(e, regles, "nomregle", tmp); // 2
rlex.debut = rg_lex(e, regles, "debut", tmp); // 3
rlex.fin = rg_lex(e, regles, "fin", tmp); // 4
rlex.occ = rg_lex(e, regles, "occ", tmp); // 5
rlex.infini = rg_lex(e, regles, "infini", tmp); // 6
rlex.commentaire = rg_lex(e, regles, "commentaire", tmp); // 7
rlex.intervalle = rg_lex(e, regles, "intervalle", tmp); // 8
rlex.hexa = rg_lex(e, regles, "hexa", tmp); // 9
rlex.car = rg_lex(e, regles, "car", tmp); // 10
rlex.reste = rg_lex(e, regles, "reste", tmp); // 11
}
WAPIDECL long parse_lex(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours)
{
#define nreg(x) ((x)*2 > trav->mLg ? 0 : *(ent16 *)(trav->mPtr + (x)*2 - 2))
/* */
static int numlig = 0;
numlig++;
/* */
if(valex->mLg == 0)
return OK; /* ligne vide */
/* */
int nbres = dynDcount(e, resultat, 10, DYN_NONE, DYN_NONE);
int nbval = dynDcount(e, valex, cVM, 2, cFM);
ent16 regle;
dynSetLen(e, trav, 0);
dynSetLen(e, encours, 0);
for(int ival = nbval; ival > 0; ival--)
{
/* suppression des regles 1 et 7 (blanc et commentaire) */
dynField(e, valex, tmp, 2, ival, cFM, cVM, 1);
regle = dynToNum(e, tmp, DYN_FALSE, 0);
if(regle == rlex.blanc || regle == rlex.commentaire)
{
dynDel(e, valex, 1, ival, cFM, cVM, 1);
dynDel(e, valex, 2, ival, cFM, cVM, 1);
dynDel(e, valex, 3, ival, cFM, cVM, 1);
}
else
{
if(dynCtrl(e, trav, trav->mLg + 2, TRUE) != DYN_OK)
return DYN_ERR;
if(trav->mLg > 0)
memcopie(trav->mPtr + 2, trav->mPtr, trav->mLg);
*(ent16 *)(trav->mPtr) = regle;
dynSetLen(e, trav, trav->mLg + 2);
}
}
//dynDel(e, valex, 2, DYN_NONE, cFM, DYN_NONE, 1);
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
//for(int i=1;i<=trav->mLg/2;i++) printf("%d,",nreg(i)); printf("\n");
/* debut d'analyse des tokens : nomregle */
if(nreg(1) != rlex.nomregle)
{
dynField(e, valex, tmp, 3, 1, cFM, cVM, 1);
printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* liste de et/ou */
for(ent16 n = 2;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == rlex.debut || regle == rlex.car) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : car ou debut et/ou attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* et */
if(n == 2)
dynStoreSz(e, valex, 4, DYN_NONE, "", 0, cFM, DYN_NONE);
else
dynConcatSz(e, valex, ";", 1);
/* */
if(regle == rlex.car)
{
/* 1 caractere = (1,1,car) (raccourci d'ecriture) */
dynConcatSz(e, valex, "1,1,", 4);
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(e, valex, tmp);
n++;
continue;
}
if(nreg(n+1) == rlex.occ && (nreg(n+2) == rlex.occ || nreg(n+2) == rlex.infini)) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : occurence min/max attendue %d\n", numlig, tmp->mPtr, n);
return DYN_ERR;
}
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
dynConcat(e, valex, encours); // occmin
n++;
if(nreg(n) == rlex.infini)
dynConcatSz(e, valex, "-1,", 3);
else
{
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
dynConcat(e, valex, encours); // occmax
}
ent16 n1,n2,n3; char unefois[2] = {0};
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
while(n1 == rlex.car || n1 == rlex.hexa || ((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa)))
{
dynConcatSz(e, valex, unefois, DYN_LGNONE);
if((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa))
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
if(n1 == 10)
dynConcat(e, valex, tmp);
else
{
dynIconv(e, tmp, encours, "X");
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
dynConcatSz(e, valex, "-", 1);
n += 2;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
if(n3 == rlex.car)
dynConcat(e, valex, tmp);
else
{
dynIconv(e, tmp, encours, "X");
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
}
else if(n1 == rlex.car)
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(e, valex, tmp);
}
else if(n1 == rlex.hexa)
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
unefois[0] = ':';
}
if(unefois[0] == 0)
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : caractere/intervalle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
if(n1 == rlex.fin) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : fin et/ou attendue\n", numlig, tmp->mPtr);
return DYN_ERR;
}
n += 2;
}
/* lecture nom regle en hexa */
dynField(e, valex, tmp, 1, 1, cFM, cVM, 1);
dynIconv(e, tmp, trav, "X");
trav->mPtr[trav->mLg - 1] = ','; /* exemple : begin,1,comment,2,... permet de faire un locate */
dynConcatSz(e, trav, Int64ToSz(e, nbres == 0 ? 1 : nbres, DYN_FALSE, 0), DYN_LGNONE);
dynStore(e, resultat, 1, nbres == 0 ? 1 : nbres*2-1, trav, 10, ',');
/* */
dynField(e, valex, tmp, 4, DYN_NONE, cFM, DYN_NONE, 1);
nbres = (nbres == 0 ? 2 : nbres + 1);
dynStoreSz(e, resultat, nbres, DYN_NONE, tmp->mPtr, tmp->mLg, 10, DYN_NONE);
/* */
#undef nreg
return OK;
}
#include "lex_files.h"
WAPIDECL long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
long cr = DYN_ERR;
if(fichier_lex != NULL)
cr = dynRead(e, regles, fichier_lex); // lire les regles depuis le fichier sur disque
else
cr = regles_lex(e, regles); // par defaut, charger les regles lex des fichiers "lex"
//
if(cr == DYN_OK)
{
dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
//dynDel(e, regles, 1, DYN_NONE, 10, DYN_NONE, 1); /* la premiere ligne contient le <numero,nom> des regles, separe par "," */
/* selon fichier_lex, lire directement depuis le source */
if(strncmp(fichier_lex, "debuglex", 8) == 0)
{
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "wlex", 4) == 0)
{
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "lexlex", 6) == 0)
{
cr = dynLet(e, regles, file_lexlex, DYN_LGNONE);
}
}
//dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
return cr;
}
//
long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
static long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
{
long conc = 1, lgconc = 0, fin = FALSE, ichaine = 0, nch, t1, t2, trouve;
long occmin, occmax, occtrouve, occsuiv;
@@ -181,8 +392,8 @@ long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dyna
conc = lgconc;
return conc;
}
//
void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
WAPIDECL void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
{
/* vars Dynamic :
regles (en entree) : liste des regles ; etregle : regle ET en cours
@@ -334,7 +545,58 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynFree(e, &motencours);
dynFree(e, &trouvemot);
}
/* source Universe (OK) :
WAPIDECL long compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile)
{
// "compile" les regles lex fournies dans <fichier_lex> et renvoi le resultat dans <compile>
// <1> = nom et numeros des regles, <2> a <n> = regles lex
long cr = DYN_OK, ret = 0;
Dynamic regles, tmp, ligne, tmp1, tmp2, tmp3;
//
dynInit(e, &regles, 0);
dynInit(e, &tmp, 0);
dynInit(e, &ligne, 0);
dynInit(e, &tmp1, 0);
dynInit(e, &tmp2, 0);
dynInit(e, &tmp3, 0);
//
dynSetLen(e, compile, 0);
//
cr = lire_regles_lex(e, &regles, "lexlex"); // <regles> = regles lex compiles
if(cr == DYN_OK)
{
init_reg_lex(e, &regles, &tmp);
dynErase(e, fichier_lex, "\r");
dynRemove(e, fichier_lex, NULL, 0, DYN_TRUE);
while(dynRemove(e, fichier_lex, &ligne, 10, DYN_FALSE) > -1 && ret == 0)
{
lex(e, &regles, &ligne, &tmp); // tmp au format "valex" : chaine/noregle/position
ret = parse_lex(e, &tmp, compile, &tmp1, &tmp2, &tmp3);
}
if(ret != 0)
cr = DYN_ERR;
}
//
dynFree(e, &regles);
dynFree(e, &tmp);
dynFree(e, &ligne);
dynFree(e, &tmp1);
dynFree(e, &tmp2);
dynFree(e, &tmp3);
//
return cr;
}
/*
pour utiliser lex :
- compiler les regles 1 fois : compile_lex(e, regles, compile)
- analyser du contenu : lex(e, compile, contenu, valex)
le resultat est dans valex : <1> chaine hexa en VM, <2> no regle en VM, <3> position origine contenu en VM
le nom de la regle <no regle> se trouve comme cela : dynField(e, compile, nom, 1, noregle*2-1, 10, ',', 1)
la conversion en clair de la chaine hexa trouvee : dynIconv(e, hexa, clair, "X");
*/
/* source OK :
* LEX.REGLE = regles Lex, valeurs ET separees par "," ; liste de cars en OU pour chaque partie ET
LEX.REGLE = ""
* 1 entete
+38
View File
@@ -0,0 +1,38 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifndef LEX_H
#define LEX_H
#include "apidecl.h"
/* utilise par genlex */
WAPIDECL void init_reg_lex(env * e, Dynamic * regles, Dynamic * tmp);
WAPIDECL long parse_lex(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours);
/* */
WAPIDECL long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex);
WAPIDECL void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex);
WAPIDECL long compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile);
#endif
+13
View File
@@ -0,0 +1,13 @@
; fichier de description du lex des fichiers lex
blanc: (1,*,#20#09) ;1; 1,-1,20:09
nomregle: (1,1,a-z) (0,*,0-9a-z) (1,1,#3A) ;2; 1,1,61-7A;0,-1,30-39:61-7A;1,1,3A
debut: (1,1,#28) ;3; 1,1,28
fin: (1,1,#29) ;4; 1,1,29
occ: (1,9,0-9) (1,1,#2C) ;5; 1,9,30-39;1,1,2C
infini: (1,1,#2A) (1,1,#2C) ;6; 1,1,2A;1,1,2C
commentaire: (1,1,#3B) (0,*,#20-#7E) ;7; 1,1,3B;0,-1,20-7E
intervalle: (1,1,#2D) ;8; 1,1,2D
hexa: (1,1,#23) (2,2,0-9A-F) ;9; 1,1,23;2,2,30-39:41-46
car: (1,1,#21-#7E) ;10; 1,1,21-7E
reste: (1,1,#00-#FF) ;11; 1,1,00-FF
+168
View File
@@ -0,0 +1,168 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_COMPILE -1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
//
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(modFnIs(e, "compile", 7))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, compile_lex(e, param1, param2));
}
}
/* ============================================================================================= */
else if(modFnIs(e, "analyze", 7))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC) // rules
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC) // input
exc = EX_MODPARAM;
else if(param3->type != VAR_DYNAMIC) // result
exc = EX_MODPARAM;
else
{
lex(e, param1, param2, param3);
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
+44
View File
@@ -0,0 +1,44 @@
// !! ne pas mettre de caracteres \r dans les constantes ci-dessous !!
// fichiers lex
static char file_lexlex[] = "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11\n"
"1,-1,20:09\n"
"1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n"
"1,1,28\n"
"1,1,29\n"
"1,9,30-39;1,1,2C\n"
"1,1,2A;1,1,2C\n"
"1,1,3B;0,-1,09-7E\n"
"1,1,2D\n"
"1,1,23;2,2,30-39:41-46\n"
"1,1,21-7E\n"
"1,1,00-FF";
// debugger w
static char file_debuglex[] = "blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,identnext,8,reste,9\n"
"1,-1,20:09:0A:0D\n"
"1,2,61-7A:41-5A\n"
"1,1,3F\n"
"1,9,30-39\n"
"1,1,2B\n"
"1,1,2D\n"
"1,1,3A;1,1,61-7A:41-5A:5F;0,23,61-7A:41-5A:30-39\n"
"1,1,2E;1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n"
"1,1,00-FF";
// langage W
static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,"
"continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,sortedsearch,60,"
"change,61,format,62,insert,63,remove,64,tonum,65,tostring,66,equal,67,diff,68,gt,69,lt,70,gte,71,lte,72,and,73,or,74,not,75,beginpar,76,endpar,77,beginh,78,endh,79,begins,80,ends,81,indirect,82,typeof,83,stringdq,84,stringq,85,ident,86,varsys,87,numberdec,88,numberint,89,minus,90,"
"plus,91,multiply,92,divide,93,divident,94,modulo,95,concat,96,listesep,97,identsep,98,modsep,99,other,100"
"\n1,-1,20:09\n1,1,3B;0,-1,00-FF\n1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n1,1,65;1,1,6E;1,1,64\n1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n"
"1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n1,1,73;1,1,75;1,1,62\n1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n1,1,69;1,1,66\n1,1,74;1,1,68;1,1,65;1,1,6E\n1,1,65;1,1,6C;1,1,73;1,1,65\n1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n"
"1,1,64;1,1,6F\n1,1,63;1,1,61;1,1,6C;1,1,6C\n1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n"
"1,1,69;1,1,6E\n1,1,6C;1,1,69;1,1,6B;1,1,65\n1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n"
"1,1,6E;1,1,6F;1,1,70\n1,1,70;1,1,61;1,1,72;1,1,74\n1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n1,1,65;1,1,63;1,1,68;1,1,6F\n1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n1,1,6C;1,1,65;1,1,74\n1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n1,1,6E;1,1,65;1,1,77\n1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n"
"1,1,74;1,1,68;1,1,69;1,1,73\n1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n1,1,68;1,1,6F;1,1,6C;1,1,64\n1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n1,1,69;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,61;1,1,63\n1,1,61;1,1,62;1,1,73\n1,1,6E;1,1,65;1,1,67\n1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,74;1,1,79;1,1,70;1,1,65\n1,1,6C;1,1,65;1,1,6E\n1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n1,1,3D\n1,1,23\n1,1,3E\n1,1,3C\n1,1,3E;1,1,3D\n1,1,3C;1,1,3D\n"
"1,1,61;1,1,6E;1,1,64\n1,1,6F;1,1,72\n1,1,6E;1,1,6F;1,1,74\n1,1,28\n1,1,29\n1,1,7B\n1,1,7D\n1,1,5B\n1,1,5D\n1,1,21\n1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n1,1,22;0,765,20-21:23-EF;1,1,22\n1,1,27;0,765,20-26:28-EF;1,1,27\n1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,40;1,-1,61-7A\n1,13,30-39;1,1,2E;0,5,30-39\n1,13,30-39\n1,1,2D\n"
"1,1,2B\n1,1,2A\n1,1,2F\n1,1,5C\n1,1,25\n1,1,3A\n1,1,2C\n1,1,2E\n1,1,26\n1,1,00-FF";
+55
View File
@@ -0,0 +1,55 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
/*
tester avec alloc (size 20) !! TODO
*/
enum {
MAX_ENTRY = 3838, // 4096 - 258
SIZE_ENTRY = (124 + sizeof(int)) // TODO : voir la meilleure taille 91 sur fichier binaire de 130 Ko... !!! tester avec 20...
};
typedef struct {
octet Dict[MAX_ENTRY * SIZE_ENTRY]; // dictionnaire en cours
int posDict; // prochaine entree a ecrire dans le dictionnaire
pointeur Alloc[MAX_ENTRY]; // pointeurs des blocs alloues en dehors des entry (car trop grand)
int allocEntry; // nb blocs alloue en dehors des entry (car trop grand)
var code; // de type dynamic, contient le code/decode en cours
var w; // de type dynamic, contient la chaine en cours d'analyse
long prec; // dernier code trouve dans le dict
long bits; // nb de bits en cours (codage/decodage)
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal)
int inverse; // "inverse" le decodage des bits LZW (cas des fichiers GIF)
} modContextLzw;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WAPIDECL void initLzw(env * e, modContextLzw * cl);
WAPIDECL void freeLzw(env * e, modContextLzw * cl);
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type);
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type);
+62 -300
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -27,17 +27,14 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "lzw.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
var dict; // de type dynamic, dictionnaire en cours
var code; // de type dynamic, contient le code/decode en cours
var w; // de type dynamic, contient la chaine en cours d'analyse
long prec; // dernier code trouve dans le dict
long posDict;// position en cours du code dans dict + 256 (dernier)
long bits; // nb de bits en cours (codage/decodage)
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal)
modContextLzw cl;
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
@@ -51,32 +48,32 @@ static int setError(modEtat * p, int err)
return err == OK ? OK : EX_MODERR;
}
long set(env * e, var * clair, modEtat * pe, int type);
long get(env * e, var * code, modEtat * pe, int type);
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
/* */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -87,84 +84,89 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
dynInit(e, &p_etat->dict, 4096);
dynInit(e, &p_etat->code, 4096);
dynInit(e, &p_etat->w, 256);
initLzw(e, &p_etat->cl);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
freeLzw(e, &p_etat->cl);
//*** FIN du code specifique ici
memfree(e, p_etat);
//*** code specifique ici
dynFree(e, &p_etat->dict);
dynFree(e, &p_etat->code);
dynFree(e, &p_etat->w);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "set", 3))
{
/* compression du clair de param, en une fois */
/* sinon utiliser : setinit, setnext, setend */
/*exc = setError(p_etat, EXMOD_xxx);*/
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, set(e, param, p_etat, 0)); /* 0 : en une fois */
}
exc = setError(p_etat, setLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
}
/* ============================================================================================= */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
/* decompression du code de param, en une fois */
/* sinon utiliser getinit, getnext, getend */
/*exc = setError(p_etat, EXMOD_xxx);*/
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, get(e, param, p_etat, 0)); /* 0 : en une fois */
p_etat->cl.inverse = FALSE;
if(param2 != NULL)
{
if(param2->type == VAR_DYNAMIC || param2->type == VAR_NUMBER)
{
number inv;
if(var_conv_num(e, param2, &inv))
p_etat->cl.inverse = (inv != 0 ? TRUE : FALSE);
}
}
exc = setError(p_etat, getLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "xxx", 3) == 0)
{
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
exc = setError(p_etat, EXMOD_xxx);
}
/* ----------------------------------------------------------------------------------------------- */
else
{
@@ -174,243 +176,3 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
return exc;
}
/* **************************************************************************************************** */
void ecrireCode(env * e, modEtat * pe, long num)
{
long b = pe->bits; /* nb bits a ecrire */
/* ecrire dans pe->code le numero num selon pe->bits (9 10 11 12) */
/* il y a entre 1 et 3 octets a ecrire dans pe->code */
if(pe->code.mInternal > 0)
{
/* finir de remplir le dernier octet de pe->code : de 1 a 7 bits */
b -= pe->code.mInternal;
pe->code.ptr[pe->code.mLg - 1] |= (num >> b); /* il reste b bits a ecrire maintenant */
}
dynCtrl(e, &pe->code, pe->code.mLg + (b > 8 ? 2 : 1), 1); /* tester code retour ? */
if(b > 7)
{
/* ecrire un octet complet */
b -= 8;
pe->code.ptr[pe->code.mLg++] = (b ? (num >> b) : num) & 255;
}
if(b > 0)
{
/* ajouter les derniers bits */
b = 8 - b;
pe->code.ptr[pe->code.mLg++] = (num << b) & 255;
}
pe->code.mInternal = b; /* nb bits libres restant */
}
long set(env * e, var * clair, modEtat * pe, int type)
{
long pos;
/* codage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
dynSetLen(e, &pe->dict, 0);
dynSetLen(e, &pe->code, 0);
pe->code.mInternal = 0; /* nb de bits libres dans le dernier octet utilise de pe->code */
dynLet(e, &pe->w, sFM, 1); /* pour simplifier le concat plus loin */
pe->prec = -1;
pe->posDict = 258;
pe->bits = 9;
}
long lg_clair = clair->mLg;
unsigned char c;
char h[3] = {0}; /* c, en faux-hexa de a=0 jusqu'a p=15 (codes ascii 97 a 112) */
unsigned char * pclair = clair->ptr; /* ptr en unsigned */
while(lg_clair--)
{
c = *pclair++;
h[0] = (c / 16) + 97;
h[1] = (c % 16) + 97;
dynConcatSz(e, &pe->w, h, 2);
/* */
if(pe->w.mLg == 3)
{
/* code simple : trouve */
pe->prec = (long)c;
}
else if((pos = dynLocateSz(e, &pe->dict, pe->w.mPtr + 1, cFM, DYN_NONE, DYN_NONE)) > 0) /* ne pas chercher le FM en debut de w */
{
/* code compose trouve */
pe->prec = pos + 256;
}
else
{
/* pas trouve */
/* 1. ecriture de pe->prec dans pe->code */
ecrireCode(e, pe, pe->prec);
/* 2. ajout de w au dict */
dynConcat(e, &pe->dict, &pe->w);
/* 3. gestion changement bits */
if(pe->posDict == 511 || pe->posDict == 1023 || pe->posDict == 2047)
pe->bits++; /* passage a 10,11,12 bits */
if(pe->posDict == 4095)
{
/* 3.1 ecrire 256 (raz bits) */
ecrireCode(e, pe, 256);
/* 3.2 raz dict */
dynSetLen(e, &pe->dict, 0);
pe->posDict = 258;
pe->bits = 9;
}
else
pe->posDict++;
/* 4. w = c */
dynLet(e, &pe->w, sFM, 1);
dynConcatSz(e, &pe->w, h, 2);
pe->prec = (long)c;
}
}
if(type == 3 || type == 0)
{
/* ecrire pe->prec (dernier code en cours) */
if(pe->prec > -1)
ecrireCode(e, pe, pe->prec);
/* ecrire 257 */
ecrireCode(e, pe, 257);
/* copie du resultat dans le parametre en sortie */
dynLet(e, clair, pe->code.mPtr, pe->code.mLg);
}
/* */
return OK;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
long get(env * e, var * comp, modEtat * pe, int type)
{
long v; /* code en cours de decodage */
unsigned char * p;
long masque[8] = {0, 1, 3, 7, 15, 31, 63, 127};
/* decodage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
dynSetLen(e, &pe->dict, 0);
dynSetLen(e, &pe->code, 0);
pe->code.mInternal = 0; /* nb bits restant en entree, a traiter (contenu dans pe->reste) */
pe->reste = 0;
dynSetLen(e, &pe->w, 0);
pe->prec = -1;
pe->posDict = 258;
pe->bits = 9;
}
long lg_comp = comp->mLg, lg;
char h[3] = {0};
unsigned char c;
unsigned char * pcomp = comp->ptr; /* ptr en unsigned */
while(lg_comp--)
{
/* lire les bits pour trouver le prochain code */
c = *pcomp++;
/* */
pe->reste = (pe->reste << 8) | c;
pe->code.mInternal += 8;
if(pe->code.mInternal < pe->bits)
continue;
pe->code.mInternal -= pe->bits; /* maxi 7 bits restants */
if(pe->code.mInternal == 0)
v = pe->reste;
else
v = pe->reste >> pe->code.mInternal;
pe->reste &= masque[pe->code.mInternal];
/* */
if(v == 256)
{
/* raz dict */
dynSetLen(e, &pe->dict, 0);
pe->posDict = 258;
pe->bits = 9;
pe->prec = -1;
continue;
}
if(v == 257)
break;
/* v est-il dans le dictionnaire ? */
if(v < pe->posDict)
{
/* *** oui *** */
/* ecrire dans le clair (pe->code) le dict[v] */
if(v < 256)
{
dynCtrl(e, &pe->code, pe->code.mLg + 1, 1);
pe->code.ptr[pe->code.mLg++] = (unsigned char)v;
h[0] = (v / 16) + 97;
h[1] = (v % 16) + 97;
}
else
{
dynField(e, &pe->dict, &pe->w, v - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
/* garder en memoire le premier caractere du dict (h) */
h[0] = pe->w.mPtr[0];
h[1] = pe->w.mPtr[1];
dynSetLen(e, &pe->w, 2);
}
if(pe->prec != -1)
{
/* recup dict<pe->prec> dans w */
if(pe->prec < 256)
{
pe->w.ptr[0] = (pe->prec / 16) + 97;
pe->w.ptr[1] = (pe->prec % 16) + 97;
dynSetLen(e, &pe->w, 2);
}
else
dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* ajout premier car du dict<v> (h) */
dynConcatSz(e, &pe->w, h, 2);
/* ecrire le nouveau dict */
dynConcatSz(e, &pe->dict, sFM, 1);
dynConcat(e, &pe->dict, &pe->w);
pe->posDict++;
if(pe->posDict == 511 || pe->posDict == 1023 || pe->posDict == 2047)
pe->bits++; /* bug passage a 10,11,12 bits */
}
}
else
{
/* *** non *** */
/* recup dict<pe->prec> dans w (ici, pe->prec ne peut pas etre a -1) */
if(pe->prec < 256)
{
pe->w.ptr[0] = (pe->prec / 16) + 97;
pe->w.ptr[1] = (pe->prec % 16) + 97;
dynSetLen(e, &pe->w, 2);
}
else
dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* ajout premier car du dict<pe->prec> (w) a sa fin elle meme (w) */
h[0] = pe->w.mPtr[0];
h[1] = pe->w.mPtr[1];
dynConcatSz(e, &pe->w, h, 2);
/* ecrire w dans le clair, w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
/* ecrire le nouveau dict */
dynConcatSz(e, &pe->dict, sFM, 1);
dynConcat(e, &pe->dict, &pe->w);
pe->posDict++;
if(pe->posDict == 511 || pe->posDict == 1023 || pe->posDict == 2047)
pe->bits++; /* bug : passage a 10,11,12 bits */
}
pe->prec = v;
}
/* */
if(type == 3 || type == 0)
{
/* traiter les bits restant (y-en-a-t-il ?) => a priori, tout a deja ete traite avant... */
/* copie du resultat dans le parametre en sortie */
dynLet(e, comp, pe->code.mPtr, pe->code.mLg);
}
/* */
return OK;
}
+390
View File
@@ -0,0 +1,390 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "lzw.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
static void InitDict(env * e, modContextLzw * cl)
{
cl->posDict = 0; // prochaine entree
// pour chaque entree, liberer tout bloc alloue (quand lg < 0 de l'entree)
for(int alloc = 0; alloc < cl->allocEntry ; alloc++)
memfree(e, cl->Alloc[alloc]);
cl->allocEntry = 0;
}
static int SearchDictEntry(env * e, modContextLzw * cl, pointeur valeur, int lg)
{
// Dict => 0-255 : idem ; 256 : EOF ; 257 : RAZ nb bits ; 258-4095 : entrees
if(lg <= 1)
return *valeur;
pointeur pDict = cl->Dict;
for(int entry = 0; entry < cl->posDict; entry++, pDict += SIZE_ENTRY)
if(lg == *(int *)(pDict))
{
if(memcmp(valeur, pDict + sizeof(int), lg) == 0)
return entry + 258;
}
else if(-lg == *(int *)(pDict))
{
// bloc alloue en dehors de l'entry (trop grand)
if(memcmp(valeur, *(pointeur *)(pDict + sizeof(int)), lg) == 0)
return entry + 258;
}
return -1; // non trouve
}
static pointeur GetDictEntry(env * e, modContextLzw * cl, int entry, int * lg)
{
entry -= 258;
if(entry < 0 || entry >= cl->posDict)
return NULL;
pointeur pDict = cl->Dict + entry * SIZE_ENTRY;
if((*lg = *(int *)(pDict)) > 0)
return pDict + sizeof(int);
else
{
*lg = abs(*lg);
return *(pointeur *)(pDict + sizeof(int));
}
}
static int AddDictEntry(env * e, modContextLzw * cl, pointeur valeur, int lg)
{
if(cl->posDict < MAX_ENTRY && lg > 0)
{
if(lg <= SIZE_ENTRY - sizeof(int))
{
pointeur pDict = cl->Dict + cl->posDict * SIZE_ENTRY;
*(int *)pDict = lg;
memcpy(pDict + sizeof(int), valeur, lg);
cl->posDict++;
return 1; // TRUE : ok
}
else
{
// mettre la longueur en negatif et allouer un bloc de la bonne taille
pointeur alloc = memalloc(e, lg);
if(alloc)
{
cl->Alloc[cl->allocEntry++] = alloc;
//
pointeur pDict = cl->Dict + cl->posDict * SIZE_ENTRY;
*(int *)pDict = -lg;
*(pointeur *)(pDict + sizeof(int)) = alloc;
memcpy(alloc, valeur, lg);
cl->posDict++;
return 1;
}
else
return 0;
}
}
else
return 0;
}
static void ecrireCode(env * e, modContextLzw * cl, long num)
{
long b = cl->bits; /* nb bits a ecrire */
/* ecrire dans cl->code le numero num selon cl->bits (9 10 11 12) */
/* il y a entre 1 et 3 octets a ecrire dans cl->code */
if(cl->code.mInternal > 0)
{
/* finir de remplir le dernier octet de cl->code : de 1 a 7 bits */
b -= cl->code.mInternal;
cl->code.ptr[cl->code.mLg - 1] |= (num >> b); /* il reste b bits a ecrire maintenant */
}
dynCtrl(e, &cl->code, cl->code.mLg + (b > 8 ? 2 : 1), 1); /* tester code retour ? */
if(b > 7)
{
/* ecrire un octet complet */
b -= 8;
cl->code.ptr[cl->code.mLg++] = (b ? (num >> b) : num) & 255;
}
if(b > 0)
{
/* ajouter les derniers bits */
b = 8 - b;
cl->code.ptr[cl->code.mLg++] = (num << b) & 255;
}
cl->code.mInternal = b; /* nb bits libres restant */
}
/* ***** PUBLIC *************** */
WAPIDECL void initLzw(env * e, modContextLzw * cl)
{
cl->allocEntry = 0;
dynInit(e, &cl->code, 4096);
dynInit(e, &cl->w, 256);
}
WAPIDECL void freeLzw(env * e, modContextLzw * cl)
{
dynFree(e, &cl->code);
dynFree(e, &cl->w);
}
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type)
{
/* codage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
InitDict(e, cl);
dynSetLen(e, &cl->code, 0);
cl->code.mInternal = 0; /* nb de bits libres dans le dernier octet utilise de pe.le->code */
dynSetLen(e, &cl->w, 0);
cl->prec = -1;
cl->bits = 9;
}
long pos, lg_clair = clair->mLg;
unsigned char c[2], * pclair = clair->ptr; /* ptr en unsigned */
c[1] = 0;
while(lg_clair--)
{
c[0] = *pclair++;
dynConcatSz(e, &cl->w, (char *)c, 1);
/* */
if(cl->w.mLg == 1)
{
/* code simple : trouve */
cl->prec = c[0];
}
else if((pos = SearchDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg)) > -1)
{
/* code compose trouve */
cl->prec = pos;
}
else
{
/* pas trouve */
/* 1. ecriture de cl->prec dans cl->code */
ecrireCode(e, cl, cl->prec);
/* 2. ajout de w au dict */
AddDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg);
/* 3. gestion changement bits */
if(cl->posDict == 512 - 258 || cl->posDict == 1024 - 258 || cl->posDict == 2048 - 258)
cl->bits++; /* passage a 10,11,12 bits */
if(cl->posDict == 4096 - 258)
{
/* 3.1 ecrire 256 (raz bits) */
ecrireCode(e, cl, 256);
/* 3.2 raz dict */
InitDict(e, cl);
cl->bits = 9;
}
/* 4. w = c */
*cl->w.ptr = c[0];
dynSetLen(e, &cl->w, 1);
cl->prec = c[0];
}
}
if(type == 3 || type == 0)
{
/* ecrire cl->prec (dernier code en cours) */
if(cl->prec > -1)
ecrireCode(e, cl, cl->prec);
/* ecrire 257 */
ecrireCode(e, cl, 257);
/* copie du resultat dans le parametre en sortie */
dynLet(e, clair, cl->code.mPtr, cl->code.mLg);
InitDict(e, cl);
}
/* */
return OK;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type)
{
long v; /* code en cours de decodage */
long masque[13] = {0, 1, 3, 7, 15, 31, 63, 127, 0, 511, 1023, 2047, 4095}; // les 8 premiers servent au mode normal, les 4 derniers au mode "inverse"
/* decodage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
InitDict(e, cl);
dynSetLen(e, &cl->code, 0);
cl->code.mInternal = 0; /* nb bits restant en entree, a traiter (contenu dans cl->reste) */
cl->reste = 0;
dynSetLen(e, &cl->w, 0);
cl->prec = -1;
cl->bits = 9;
}
long lg_comp = comp->mLg;
int lg;
unsigned char c, h[2];
unsigned char * pcomp = comp->ptr; /* ptr en unsigned */
pointeur pEntry;
h[1] = 0;
while(lg_comp--)
{
/* lire les bits pour trouver le prochain code */
c = *pcomp++;
/* */
if(cl->inverse) // test, sinon param "inverse"
{
// cas LZW du giff (different de LZW natif/PDF !)
if(cl->code.mInternal == 0)
cl->reste |= c;
else
cl->reste |= (c << cl->code.mInternal);
cl->code.mInternal += 8;
if(cl->code.mInternal < cl->bits)
continue;
v = (cl->reste & masque[cl->bits]);
cl->reste >>= cl->bits;
cl->code.mInternal -= cl->bits;
}
else
{
cl->reste = (cl->reste << 8) | c;
cl->code.mInternal += 8;
if(cl->code.mInternal < cl->bits)
continue;
cl->code.mInternal -= cl->bits; /* maxi 7 bits restants */
if(cl->code.mInternal == 0)
v = cl->reste;
else
v = cl->reste >> cl->code.mInternal;
cl->reste &= masque[cl->code.mInternal];
}
/* */
if(v == 256)
{
/* raz dict */
InitDict(e, cl);
cl->bits = 9;
cl->prec = -1;
continue;
}
if(v == 257)
break;
/* v est-il dans le dictionnaire ? */
if(v - 258 < cl->posDict)
{
/* *** oui *** */
/* ecrire dans le clair (cl->code) le dict[v] */
if(v < 256)
{
h[0] = v;
dynConcatSz(e, &cl->code, (char *)h, 1);
}
else
{
pEntry = GetDictEntry(e, cl, v, &lg);
//dynField(e, &pe->dict, &pe->w, v - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
//dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
//for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
// pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
dynConcatSz(e, &cl->code, (char *)pEntry, lg);
/* garder en memoire le premier caractere du dict (h) */
h[0] = *pEntry;
*cl->w.mPtr = *pEntry; // utilite ? a mettre en commentaire
dynSetLen(e, &cl->w, 1); // utilite ? a mettre en commentaire
}
if(cl->prec != -1)
{
/* recup dict<cl->prec> dans w */
if(cl->prec < 256)
{
*cl->w.mPtr = cl->prec;
dynSetLen(e, &cl->w, 1);
}
else
{
//dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
pEntry = GetDictEntry(e, cl, cl->prec, &lg);
dynLet(e, &cl->w, (char *)pEntry, lg);
}
/* ajout premier car du dict<v> (h) */
dynConcatSz(e, &cl->w, (char *)h, 1);
/* ecrire le nouveau dict */
AddDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg);
//dynConcatSz(e, &pe->dict, sFM, 1);
//dynConcat(e, &pe->dict, &pe->w);
//cl->posDict++;
if(cl->posDict == 511 - 258 || cl->posDict == 1023 - 258 || cl->posDict == 2047 - 258)
cl->bits++;
}
}
else
{
/* *** non *** */
/* recup dict<cl->prec> dans w (ici, cl->prec ne peut pas etre a -1) */
if(cl->prec < 256)
{
*cl->w.mPtr = cl->prec;
dynSetLen(e, &cl->w, 1);
}
else
{
//dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
pEntry = GetDictEntry(e, cl, cl->prec, &lg);
dynLet(e, &cl->w, (char *)pEntry, lg);
}
/* ajout premier car du dict<cl->prec> (w) a sa fin elle meme (w) */
h[0] = *cl->w.mPtr;
//h[1] = pe->w.mPtr[1];
dynConcatSz(e, &cl->w,(char *) h, 1);
/* ecrire w dans le clair, w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
//dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
//for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
// pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
dynConcatSz(e, &cl->code, cl->w.mPtr, cl->w.mLg);
/* ecrire le nouveau dict */
AddDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg);
//dynConcatSz(e, &pe->dict, sFM, 1);
//dynConcat(e, &pe->dict, &pe->w);
//cl->posDict++;
if(cl->posDict == 511 - 258 || cl->posDict == 1023 - 258 || cl->posDict == 2047 - 258)
cl->bits++;
}
cl->prec = v;
}
/* */
if(type == 3 || type == 0)
{
/* traiter les bits restant (y-en-a-t-il ?) => a priori, tout a deja ete traite avant... */
/* copie du resultat dans le parametre en sortie */
dynLet(e, comp, cl->code.mPtr, cl->code.mLg);
InitDict(e, cl);
}
/* */
return OK;
}
+11 -5
View File
@@ -44,6 +44,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#define WLIBDECL __declspec(dllexport)
#else
#define WLIBDECL
#endif
#ifndef UNIX
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
@@ -74,7 +80,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -88,7 +94,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
@@ -96,7 +102,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -111,7 +117,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -127,7 +133,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "xxx", 3) == 0)
else if(modFnIs(e, "xxx", 3))
{
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
exc = setError(p_etat, EXMOD_xxx);
+89
View File
@@ -0,0 +1,89 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "lzw.h"
/* ******* constantes ********** */
enum {
PDFFMT_A4P = 1, /* A4 portrait */
PDFFMT_A4L = 2, /* A4 paysage ("landscape") */
PDFFMT_A3P = 3, /* A3 portrait */
PDFFMT_A3L = 4, /* A3 paysage */
PDFFONT_COURIER = 1,
PDFFONT_COURIER_BOLD = 2,
PDFFONT_COURIER_BOLDOBLIQUE = 3,
PDFFONT_COURIER_OBLIQUE = 4,
PDFFONT_HELVETICA = 5,
PDFFONT_HELVETICA_BOLD = 6,
PDFFONT_HELVETICA_BOLDOBLIQUE = 7,
PDFFONT_HELVETICA_OBLIQUE = 8,
PDFFONT_TIMES_ROMAN = 9,
PDFFONT_TIMES_BOLD = 10,
PDFFONT_TIMES_ITALIC = 11,
PDFFONT_TIMES_BOLDITALIC = 12,
PDFFONT_SYMBOL = 13,
PDFFONT_ZAPFDINGBATS = 14,
PDFFONT_NB = 14
};
/* ***** MACRO ****/
#define RGB(r,g,b) (((((r&255)<<8)+(g&255))<<8)+(b&255))
typedef struct
{
Dynamic mPdf; /* PDF en cours de constitution */
Dynamic mPage; /* page en cours */
Dynamic mXref; /* liste des xref du PDF en cours (<1> contient le titre et les dimensions des images) */
Dynamic mImg; /* images en FM, en hexa, BMP 24/32 bpp uniquement (codage RGB) */
long mNbPage; /* nb de pages total du PDF */
long mFormat; /* A4 ou A3 et Paysage ou portrait */
long mLarg, mHaut; /* largeur/hauteur de la page en (mm x 10), selon le format */
long mNbObj; /* pour xref */
long mNumPage; /* numero page en cours */
long mLmarg; /* marge gauche en mm x 10 */
long mRmarg; /* marge droite en mm x 10 */
long mHmarg; /* marge haute en mm x 10 */
long mBmarg; /* marge basse en mm x 10 */
long mDimFont; /* taille fonte */
long mDimFontCadre;
long mDimLig;
Dynamic mFont; /* nom des 14 fontes standards */
modContextLzw mCtxLzw; /* gestion compression page lzw */
Dynamic mTmp1, mTmp2, mTmp3; /* temporaire pour le traitement */
} modContextPdf;
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf);
WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts);
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression);
WAPIDECL int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt);
WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille);
WAPIDECL int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img);
WAPIDECL int pdfDeleteImage(env * e, modContextPdf * ctxPdf, long img);
WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier);
WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic * lignes, long format);
+375
View File
@@ -0,0 +1,375 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
#include "pdf.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextPdf cp;
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initPdf(e, &p_etat->cp);
}
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
freePdf(e, &p_etat->cp);
// fin liberation specifique module avant arret process
memfree(e, p_etat);
}
}
else if(modFnIs(e, "vers", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(modFnIs(e, "beginDoc", 8))
{
// nouveau document pdf
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// lire les infos necessaires a la creation d'un nouveau doc. pdf :
// titre, nb pages, format, fontes utilisees
var * titre, * fontes, * nbPage, * format;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fontes"), &fontes);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Pages"), &nbPage);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Format"), &format);
if(titre && fontes && nbPage && format)
{
if(titre->type == VAR_DYNAMIC && fontes->type == VAR_DYNAMIC && nbPage->type == VAR_NUMBER && format->type == VAR_NUMBER)
{
number nnbPage, nformat;
if( var_conv_num(e, nbPage, &nnbPage) && var_conv_num(e, format, &nformat) )
exc = setError(p_etat, ! newPdf(e, &p_etat->cp, titre, nnbPage / NUM_FACTEUR, nformat / NUM_FACTEUR, fontes));
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "endDoc", 6))
{
// finalise le document pdf, et renvoi le contenu dans param1
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
int cr = endPdf(e, &p_etat->cp);
if(cr)
{
var_let(e, param1, getPdf(e, &p_etat->cp), FALSE, FALSE);
}
exc = setError(p_etat, ! cr);
}
}
/* ============================================================================================= */
else if(modFnIs(e, "addPage", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
// ajouter la page en cours au doucment pdf
exc = setError(p_etat, ! setPdfPage(e, &p_etat->cp, 1)); // 1 = avec compression ; parametrer ?
}
/* ============================================================================================= */
else if(modFnIs(e, "addText", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// ajouter le texte
var * x, * y, * w, * h; // cadre englobant
var * fonte, * taille, * couleur;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fonte"), &fonte);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Taille"), &taille);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Couleur"), &couleur);
if(x && y && w && h && fonte && taille && couleur)
{
number nx, ny, nw, nh, nfonte, ntaille, ncouleur;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
var_conv_num(e, fonte, &nfonte) && var_conv_num(e, taille, &ntaille) && var_conv_num(e, couleur, &ncouleur) )
exc = setError(p_etat, ! setPdfText(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
nfonte / NUM_FACTEUR, ntaille / NUM_FACTEUR, ncouleur / NUM_FACTEUR, param2)); // param2 = texte
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "delImage", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER && param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number indice;
if(var_conv_num(e, param1, &indice))
exc = setError(p_etat, ! pdfDeleteImage(e, &p_etat->cp, indice / NUM_FACTEUR));
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "addGraph", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * w, * h; // cadre englobant
var * couleurTrait, * couleurRemplissage, * epaisseur, * pointille, * type;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CouleurTrait"), &couleurTrait);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CouleurRemplissage"), &couleurRemplissage);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "EpaisseurTrait"), &epaisseur);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Pointille"), &pointille);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Type"), &type);
if(x && y && w && h && couleurTrait && couleurRemplissage && epaisseur && pointille && type)
{
number nx, ny, nw, nh, ntrait, nrempl, nepais, npoint;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
type->type == VAR_DYNAMIC && var_conv_num(e, couleurTrait, &ntrait) && var_conv_num(e, couleurRemplissage, &nrempl) &&
var_conv_num(e, epaisseur, &nepais) && var_conv_num(e, pointille, &npoint) )
exc = setError(p_etat, ! setPdfGraph(e, &p_etat->cp, *type->mPtr, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
ntrait / NUM_FACTEUR, nrempl / NUM_FACTEUR, nepais / NUM_FACTEUR, npoint / NUM_FACTEUR));
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "addImage", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * img; // cadre englobant et n° image
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Image"), &img);
if(x && y && img)
{
number nx, ny, nimg;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, img, &nimg) )
exc = setError(p_etat, ! setPdfImage(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nimg / NUM_FACTEUR));
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "loadImage", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, ! pdfLoadImageBmp(e, &p_etat->cp, param1));
}
}
/* ============================================================================================= */
else if(modFnIs(e, "listing", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
var * titre, * format;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Format"), &format);
if(titre && format)
{
if(titre->type == VAR_DYNAMIC && format->type == VAR_NUMBER)
{
int cr = pdfList(e, &p_etat->cp, titre, param2, format->num / NUM_FACTEUR);
if(cr)
{
var_let(e, param2, getPdf(e, &p_etat->cp), FALSE, FALSE);
}
exc = setError(p_etat, ! cr);
}
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
+750
View File
@@ -0,0 +1,750 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "pdf.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
//
// creation fichier PDF
//
// structure fichier PDF :
// header - body - xref table - trailer
//
// header :
// %PDF-1.2 : version du fichier
//
// xref table :
// xref
// "no objet debut" "nb objet" --> no objet debut = 0 le plus souvent
// "offset R%10" "00000" n EOL (20 octets pile, autant que de nb objet ; utilise)
// "objet libre suiv R%10" "generation num R%5" f EOL (20 octets pile, autant que de nb objet ; libre)
// si pas d'objets libres, le zero est toujours libre (debut de la liste chainee : 0000000000 65535 f)
//
// trailer :
// trailer << "liste cle/valeur" >>
// startxref
// "offset xref-table"
// %%EOF
// cle/valeur obligatoires :
// /Size "nb xref" : nb d'objet dans la xref table --> = "nb objet" de xref
// /Root "N" 0 R : reference a l'objet de depart du fichier, numero "N" (sauf 0)
// facultatif /Info "N" 0 R --> liste des infos possibles dans l'objet "N" :
// N 0 R << /Producer (Nom du logiciel)
// /Title (Titre)
// /Author (Nom prenom)
// /Creator ()
// /Subject ()
// /Keywords ()
// /CreationDate (D:20120906140053) --> format des dates au passage ici
// >>
//
// body :
// contient la liste des objets, structure :
// catalog - page tree - liste des pages
//
// commentaires :
// % "bla bla bla .." jusqu'à la fin de la ligne
// dans un "stream" uniquement
//
// catalog :
// 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
// Type et Pages sont obligatoires
//
// page tree :
// 2 0 obj << /Type /Pages /Count 3 /Kids [ 3 0 R 4 0 R 5 0 R ] >> end obj
// Type, Count et Kids sont obligatoires
//
// page :
// 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [ x1 y1 x2 y2 ]
// /Resources << "ressources de la page : police, etc." >>
// /Contents 6 0 R --> contenu de la page dans l'objet 6
// >> end obj
// Type et Parent sont obligatoires ; Resources et Contents sont heritables
//
// ressources :
// /Font << /F1 7 0 R >>
//
// contenu : objet 6
// 6 0 obj << /Length 123 >>
// stream
// ... "contenu : BT, etc. de longueur 123 octets" ...
// endstream
// endobj
//
// fonte no 1 :
// 7 0 obj << /Type /Font /Subtype /Type1 (ou "/TrueType" mais necessite plus d'infos)
// /Name F1 /BaseFont Helvetica (ou "Courier" "Times-Roman" "Helvetica-Bold" "Courier-Bold" "Times-Bold")
// >> endobj
//
// Coordonnees :
//
// y ^
// |
// |
// 0 +------> user space en 1/72 de pouce (=25.4mm)
// 0 x
// ex. A4 = 210x297 = 595x841 (mm a multiplier par 2.835) ; 1 cm = 28 user space ; 1 userspace = 0.35 mm)
// nb avec decimale possible : ex : 594.25, etc.
//
// zones de texte (dans un "stream") :
// BT --> debut texte
// /F13 12 Tf --> choix fonte 13 (cf. /Resources) en taille 12
// 288 720 Td --> positionnement x y
// (ABC) Tj --> texte a editer
// ET --> fin texte
//
// rectangle ("stream") :
// "x y w h" re S
// ligne :
// x1 y1 m x2 y2 l S
//
// Path clipping :
// utiliser l'opérateur "W n" pour définir une région de clipping (à mettre pour les zones texte)
//
// EXEMPLE (enlever les // de chaque debut de ligne...) -----------------------------------------------------------------------------
//
// %PDF-1.2
// 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
// 2 0 obj << /Type /Pages /Count 1 /Kids [ 3 0 R ] >> end obj
// 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [ 0 0 595 841 ] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >> end obj
// 4 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /BaseFont /Courier >> endobj
// 5 0 obj << /Length 95 >>
// stream
// % Page 1
// 188 720 15 15 re W n
// BT
// /F1 10 Tf 188 720 Td (ABC) Tj
// ET
// 0 w
// 188 730 80 40 re S
// endstream
// endobj
// xref
// 0 6
// 0000000000 65535 f
// 0000000010 00000 n
// 0000000060 00000 n
// 0000000121 00000 n
// 0000000252 00000 n
// 0000000331 00000 n
// trailer
// << /Size 6 /Root 1 0 R >>
// startxref
// 481
// %%EOF
//
#include "stdio.h"
enum {
PDF_CONV1 = 72000,
PDF_CONV2 = 2540
};
/* valeur en dixieme de mm * CONV11 / CONV2 = valeur en unites pdf x 100 (72 dpi = 72 points par pouce ; 1 pouce = 25.4) */
/* PRIVATE *****************************************************/
static int pdfEchap(env * e, Dynamic * resultat, Dynamic * chaine)
{
char * p, * q, c;
long lg = chaine->mLg, nb = 0;
/* d'abord compter les caracteres a "echapper" */
p = chaine->mPtr;
while((c=*p++))
if(c == '(' || c == ')' || c == '\\')
nb++;
/* ensuite, preparer la chaine resultat (lg + nb) */
if(dynCtrl(e, resultat, lg + nb, FALSE))
return FALSE; // erreur memoire
/* enfin, recopier les caracteres et prefixer ( ) \ par \ */
p = chaine->mPtr;
q = resultat->mPtr;
while((c=*p++))
{
if(c == '(' || c == ')' || c == '\\')
*q++ = '\\';
*q++ = c;
}
dynSetLen(e, resultat, lg + nb);
return TRUE;
}
static int setXref(env * e, modContextPdf * ctxPdf)
{
/* calcule la taille actuelle du PDF (pour calcul offset) avec saut de ligne meme sur la derniere ligne */
return ! dynConcatSz(e, &ctxPdf->mXref, sFM, 1) && ! dynConcatSz(e, &ctxPdf->mXref, Int64ToSz(e, (ent64s)ctxPdf->mPdf.mLg, FALSE, 10), DYN_LGNONE); // verif leftpad ok (idem "%010ld") !! TODO !!
}
static char table100[400] = ".00\0.01\0.02\0.03\0.04\0.05\0.06\0.07\0.08\0.09\0"
".10\0.11\0.12\0.13\0.14\0.15\0.16\0.17\0.18\0.19\0"
".20\0.21\0.22\0.23\0.24\0.25\0.26\0.27\0.28\0.29\0"
".30\0.31\0.32\0.33\0.34\0.35\0.36\0.37\0.38\0.39\0"
".40\0.41\0.42\0.43\0.44\0.45\0.46\0.47\0.48\0.49\0"
".50\0.51\0.52\0.53\0.54\0.55\0.56\0.57\0.58\0.59\0"
".60\0.61\0.62\0.63\0.64\0.65\0.66\0.67\0.68\0.69\0"
".70\0.71\0.72\0.73\0.74\0.75\0.76\0.77\0.78\0.79\0"
".80\0.81\0.82\0.83\0.84\0.85\0.86\0.87\0.88\0.89\0"
".90\0.91\0.92\0.93\0.94\0.95\0.96\0.97\0.98\0.99\0";
static int fmt2(env * e, Dynamic * res, ent64s a, ent64s b)
{
int cr = TRUE;
ent64s r = a * PDF_CONV1 / PDF_CONV2;
cr = cr && !dynConcatSz(e, res, Int64ToSz(e, r / 100, TRUE, 0), DYN_LGNONE) && !dynConcatSz(e, res, &table100[(abs(r) % 100) * 4], 3) && !dynConcatSz(e, res, " ", 1);
r = b * PDF_CONV1 / PDF_CONV2;
cr = cr && !dynConcatSz(e, res, Int64ToSz(e, r / 100, TRUE, 0), DYN_LGNONE) && !dynConcatSz(e, res, &table100[(abs(r) % 100) * 4], 3);
return cr;
}
static int fmt4(env * e, Dynamic * res, ent64s a, ent64s b, ent64s c, ent64s d)
{
int cr = TRUE;
ent64s r = a * PDF_CONV1 / PDF_CONV2;
cr = cr && !dynConcatSz(e, res, Int64ToSz(e, r / 100, TRUE, DYN_NONE), DYN_LGNONE) && !dynConcatSz(e, res, &table100[(abs(r) % 100) * 4], 3) && !dynConcatSz(e, res, " ", 1);
r = b * PDF_CONV1 / PDF_CONV2;
cr = cr && !dynConcatSz(e, res, Int64ToSz(e, r / 100, TRUE, DYN_NONE), DYN_LGNONE) && !dynConcatSz(e, res, &table100[(abs(r) % 100) * 4], 3) && !dynConcatSz(e, res, " ", 1);
r = c * PDF_CONV1 / PDF_CONV2;
cr = cr && !dynConcatSz(e, res, Int64ToSz(e, r / 100, TRUE, DYN_NONE), DYN_LGNONE) && !dynConcatSz(e, res, &table100[(abs(r) % 100) * 4], 3) && !dynConcatSz(e, res, " ", 1);
r = d * PDF_CONV1 / PDF_CONV2;
cr = cr && !dynConcatSz(e, res, Int64ToSz(e, r / 100, TRUE, DYN_NONE), DYN_LGNONE) && !dynConcatSz(e, res, &table100[(abs(r) % 100) * 4], 3);
return cr;
}
static int fmtc(env * e, Dynamic * res, long coul)
{
int cr = TRUE;
/* utilise la var t pour renvoyer la couleur convertie en 9 9 9, avec 9 allant de 0 a 1 sur 2 decimales */
long r = (coul >> 16) & 255; // red
long g = (coul >> 8) & 255; // green
long b = coul & 255; // blue
cr = cr && !dynConcatSz(e, res, r == 255 ? "1" : "0", 1);
cr = cr && (r != 255 ? !dynConcatSz(e, res, &table100[((int)(r * 100 / 255)) * 4], 3) : TRUE);
cr = cr && !dynConcatSz(e, res, g == 255 ? " 1" : " 0", 2);
cr = cr && (g != 255 ? !dynConcatSz(e, res, &table100[((int)(g * 100 / 255)) * 4], 3) : TRUE);
cr = cr && !dynConcatSz(e, res, b == 255 ? " 1" : " 0", 2);
cr = cr && (b != 255 ? !dynConcatSz(e, res, &table100[((int)(b * 100 / 255)) * 4], 3) : TRUE);
/* */
return cr;
}
static void convertHexaRGBToBinLzw(env * e, modContextPdf * ctxPdf)
{
// ctxPdf->mTmp1 contient les donnees en entree, et ctxPdf->mTmp2 en sortie le lzw binaire
// conversion de mTmp1 RGB hexa en binaire dans mTmp2
dynSetLen(e, &ctxPdf->mTmp2, 0);
long i, nb = ctxPdf->mTmp1.mLg / 6; // RRGGBB = 6 octets
octet * p = ctxPdf->mTmp1.ptr;
char res[4] = {0};
for(i = 0; i < nb; i++, p += 6)
{
dynConvertCharHexaToChar(*p, *(p+1), res);
dynConvertCharHexaToChar(*(p+2), *(p+3), res + 1);
dynConvertCharHexaToChar(*(p+4), *(p+5), res + 2);
dynConcatSz(e, &ctxPdf->mTmp2, res, 3);
}
// compression lzw de e->mTmp2
setLzw(e, &ctxPdf->mTmp2, &ctxPdf->mCtxLzw, 0);
}
/* PUBLIC ************************************************************************/
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf)
{
ctxPdf->mLmarg = 100; /* dixieme de mm ( = 1 cm ici) */
ctxPdf->mRmarg = 100;
ctxPdf->mHmarg = 100;
ctxPdf->mBmarg = 100;
ctxPdf->mDimFont = 9;
ctxPdf->mDimFontCadre = 9;
ctxPdf->mDimLig = 9;
/* */
dynInit(e, &ctxPdf->mFont, 256);
dynInit(e, &ctxPdf->mTmp1, 1024);
dynInit(e, &ctxPdf->mTmp2, 1024);
dynInit(e, &ctxPdf->mTmp3, 1024);
dynInit(e, &ctxPdf->mPage, 4096);
dynInit(e, &ctxPdf->mPdf, 8192);
ctxPdf->mPdf.type = VAR_DYNAMIC;
dynInit(e, &ctxPdf->mXref, 1024);
dynInit(e, &ctxPdf->mImg, 2048);
/* nom des fontes standards */
dynLet(e, &ctxPdf->mFont, "Courier,Courier-Bold,Courier-BoldOblique,Courier-Oblique,Helvetica,Helvetica-Bold,Helvetica-BoldOblique,Helvetica-Oblique,"
"Times-Roman,Times-Bold,Times-Italic,Times-BoldItalic,Symbol,ZapfDingbats", DYN_LGNONE);
dynConvert(e, &ctxPdf->mFont, ",", sFM);
//
initLzw(e, &ctxPdf->mCtxLzw);
}
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf)
{
freeLzw(e, &ctxPdf->mCtxLzw);
/* */
dynFree(e, &ctxPdf->mFont);
dynFree(e, &ctxPdf->mTmp1);
dynFree(e, &ctxPdf->mTmp2);
dynFree(e, &ctxPdf->mTmp3);
dynFree(e, &ctxPdf->mPage);
dynFree(e, &ctxPdf->mPdf);
dynFree(e, &ctxPdf->mXref);
dynFree(e, &ctxPdf->mImg);
}
WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts)
{
long i, j, cpt, nbp;
long nb_img, nb_obj_entete, nb_font, nb_obj_fixe = 3;
int cr = TRUE;
/* controles */
if(nb_page < 1)
return FALSE;
/* */
switch(format)
{
/* largeur et hauteur en unités mm x 10 ici */
case PDFFMT_A4P:
ctxPdf->mLarg = 2100;
ctxPdf->mHaut = 2970;
ctxPdf->mFormat = format;
break;
case PDFFMT_A4L:
ctxPdf->mLarg = 2970;
ctxPdf->mHaut = 2100;
ctxPdf->mFormat = format;
break;
case PDFFMT_A3P:
ctxPdf->mLarg = 2970;
ctxPdf->mHaut = 4200;
ctxPdf->mFormat = format;
break;
case PDFFMT_A3L:
ctxPdf->mLarg = 4200;
ctxPdf->mHaut = 2970;
ctxPdf->mFormat = format;
break;
default:
return FALSE;
}
ctxPdf->mNbPage = nb_page;
/* raz vars dynamiques */
dynSetLen(e, &ctxPdf->mPdf, 0);
dynSetLen(e, &ctxPdf->mPage, 0);
dynSetLen(e, &ctxPdf->mXref, 0);
/* */
cr = cr && pdfEchap(e, &ctxPdf->mTmp1, titre); // dans les chaines "echapper" ( ) \ avec \( \) \\ (seuls cas)
dynConcat(e, &ctxPdf->mXref, &ctxPdf->mTmp1); // xref<1> = titre
/* */
nb_font = dynDcount(e, fonts, cFM, DYN_NONE, DYN_NONE);
nb_img = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE);
nb_obj_entete = nb_obj_fixe + nb_font + nb_img;
ctxPdf->mNbObj = nb_obj_entete + ctxPdf->mNbPage;
ctxPdf->mNumPage = 0;
//
dynLet(e, &ctxPdf->mPdf, "%PDF-1.2\r\n", DYN_LGNONE);
// objet racine root
setXref(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, "1 0 obj << /Type /Catalog /Pages 3 0 R >> endobj\r\n", DYN_LGNONE);
setXref(e, ctxPdf);
// infos sur le pdf
dynConcatSz(e, &ctxPdf->mPdf, "2 0 obj << /Producer (WPDF) /Author (WPDF) /Title (", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1); /* titre "echape" */
dynConcatSz(e, &ctxPdf->mPdf, ") /CreationDate (", DYN_LGNONE);
dynSetLen(e, &ctxPdf->mTmp1, 0); // empty => oconv will convert time of the day
dynOconv(e, &ctxPdf->mTmp1, &ctxPdf->mTmp2, "DYMDhms");
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
//dynConcatSz(e, &ctxPdf->mPdf, "20000101140000", DYN_LGNONE); // TODO date courante YMDhms dynOconv(e, ...) en TU
dynConcatSz(e, &ctxPdf->mPdf, ") >> endobj\r\n", DYN_LGNONE);
setXref(e, ctxPdf);
// liste des pages
cpt = nb_obj_entete;
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNbPage; i++)
{
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
/* liste des fontes, prendre celles utilisees */
cpt = nb_obj_fixe;
for(i = 1, nbp = 0; i <= PDFFONT_NB; i++)
{
dynField(e, &ctxPdf->mFont, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
if(dynLocateSz(e, fonts, ctxPdf->mTmp1.mPtr, cFM, DYN_NONE, DYN_NONE) > 0)
{
setXref(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Type /Font /Subtype /Type1 /Name /F", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++nbp, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " /BaseFont /", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf," /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding >> >> endobj\r\n", DYN_LGNONE);
}
}
/* liste des images */
for(i = 1; i <= nb_img; i++)
{
setXref(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Type /XObject /Subtype /Image /Width ", DYN_LGNONE);
/* ajout des coordonnes de l'image au format "w 0 0 h" de xref<1,2> a xref<1,1+nb_img> */
dynField(e, &ctxPdf->mImg, &ctxPdf->mTmp1, i, 1, cFM, cVM, 1); // vm1 = larg (w) VM2 = haut (h) VM3 = bitmap 32bpp hexa RGB
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mXref, sVM, DYN_LGNONE);
dynConcat(e, &ctxPdf->mXref, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf," /Height ", DYN_LGNONE);
dynField(e, &ctxPdf->mImg, &ctxPdf->mTmp1, i, 2, cFM, cVM, 1); // vm1 = larg (w) VM2 = haut (h) VM3 = bitmap 32bpp hexa RGB
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mXref, " 0 0 ", DYN_LGNONE);
dynConcat(e, &ctxPdf->mXref, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf," /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /LZWDecode /Length ", DYN_LGNONE); // TODO remplacer /ASCIIHexDecode par /LZWDecode
dynField(e, &ctxPdf->mImg, &ctxPdf->mTmp1, i, 3, cFM, cVM, 1); // vm1 = larg (w) VM2 = haut (h) VM3 = bitmap 32bpp hexa RGBRGBRGBRGB
convertHexaRGBToBinLzw(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mTmp2.mLg, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " >>\r\nstream\r\n", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
//dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mTmp1.mLg, FALSE, 0), DYN_LGNONE);
//dynConcatSz(e, &ctxPdf->mPdf, " >>\r\nstream\r\n", DYN_LGNONE);
//dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf,"\r\nendstream\r\nendobj\r\n", DYN_LGNONE);
}
/* definition de chaque page */
cpt = nb_obj_entete;
for(i = 1; i <= ctxPdf->mNbPage; i++)
{
setXref(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Type /Page /Parent 3 0 R /MediaBox [ 0 0 ", DYN_LGNONE);
fmt2(e, &ctxPdf->mPdf, ctxPdf->mLarg, ctxPdf->mHaut);
dynConcatSz(e, &ctxPdf->mPdf," ] /Resources << /Font << ", DYN_LGNONE);
for(j = 1; j <= nbp; j++)
{
dynConcatSz(e, &ctxPdf->mPdf, "/F", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + nb_obj_fixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
for(j = 1; j <= nb_img; j++)
{
if(j == 1)
dynConcatSz(e, &ctxPdf->mPdf, "/XObject << ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, "/Img", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + nb_obj_fixe + nbp, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R", DYN_LGNONE);
if(j == nb_img)
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> /Contents ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, i + nb_obj_entete + ctxPdf->mNbPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R >> endobj\r\n", DYN_LGNONE);
}
return cr;
}
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf)
{
long i, nb; /* nb xref */
setXref(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, "xref\r\n0 ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj + 1, FALSE, DYN_NONE), DYN_LGNONE);
nb = dynDcount(e, &ctxPdf->mXref, cFM, DYN_NONE, DYN_NONE);
for(i = 1; i < nb; i++)
if(i == 1)
/* le premier attribut ne fait pas partie de "xref" (titre) */
dynConcatSz(e, &ctxPdf->mPdf, "\r\n0000000000 65535 f\r\n", DYN_LGNONE);
else
{
dynField(e, &ctxPdf->mXref, &ctxPdf->mTmp1, i, 1, cFM, cVM, 1); // VM1 a cause des images (x et y dans xref<x,2>...)
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf, " 00000 n\r\n", DYN_LGNONE);
}
dynField(e, &ctxPdf->mXref, &ctxPdf->mTmp1, nb, DYN_NONE, cFM, DYN_NONE, 1);
dynConcatSz(e, &ctxPdf->mPdf, "trailer\r\n<< /Size ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj + 1, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " /Root 1 0 R /Info 2 0 R >>\r\nstartxref\r\n", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, dynToNum(e, &ctxPdf->mTmp1, FALSE, 10), FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, "\r\n%%EOF", DYN_LGNONE);
return TRUE;
}
WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf)
{
return &ctxPdf->mPdf;
}
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
{
int cr = TRUE;
/* compression = 0 : pas de compression LZW */
/* 1 : compression LZW en binaire */
setXref(e, ctxPdf);
ctxPdf->mNbObj++;
ctxPdf->mNumPage++;
/* ajout du code "PDF" directement */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Length ", DYN_LGNONE);
if( ! compression)
{
/* pas de compression ni codage ici */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mPage.mLg, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " >>\r\nstream\r\n", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mPage);
}
else
{
// compression LZW du stream de la page
//ctxPdf->mCtxLzw.compress_do(0, (unsigned char *)ctxPdf->mPage.mPtr, ctxPdf->mPage.mLg); // verif
setLzw(e, &ctxPdf->mPage, &ctxPdf->mCtxLzw, 0);
//ctxPdf->mPage = ctxPdf->mLzw.getCode(); // verif
/* */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mPage.mLg, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " /Filter /LZWDecode >>\r\nstream\r\n", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mPage);
}
dynConcatSz(e, &ctxPdf->mPdf, "endstream\r\nendobj\r\n", DYN_LGNONE);
/* raz page */
dynSetLen(e, &ctxPdf->mPage, 0);
return cr;
}
WAPIDECL int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt)
{
int cr = TRUE;
/* x,y,w,h en mm, font de 1 a PDF_FONT_NB, couleur avec RGB(r,g,b) */
cr = cr && pdfEchap(e, &ctxPdf->mTmp1, txt);
fmtc(e, &ctxPdf->mPage, couleur);
dynConcatSz(e, &ctxPdf->mPage, " rg q ", DYN_LGNONE);
fmt4(e, &ctxPdf->mPage, x, y, w, h);
dynConcatSz(e, &ctxPdf->mPage, " re W n BT /F", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, Int64ToSz(e, font, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, Int64ToSz(e, taille, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, " Tf ", DYN_LGNONE);
fmt2(e, &ctxPdf->mPage, x, y);
dynConcatSz(e, &ctxPdf->mPage, " Td 2 Ts (", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPage, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPage, ") Tj ET Q 0 0 0 rg\r\n", DYN_LGNONE);
return cr;
}
WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille)
{
int cr = TRUE;
/* x,y,w,h en mm, font de 1 a PDF_FONT_NB, coul_trait/coul_rempl avec RGB(r,g,b), epaisseur et pointille de 0 a 9 */
/* si couleur = -1, ne pas tenir compte */
/* type: L ligne C cadre R remplissage D cadre+remplissage */
dynConcatSz(e, &ctxPdf->mPage, "q ", DYN_LGNONE);
if(coul_trait != -1)
{
fmtc(e, &ctxPdf->mPage, coul_trait);
dynConcatSz(e, &ctxPdf->mPage, " RG ", DYN_LGNONE);
}
if(coul_rempl != -1 && type != 'L') /* pas de remplissage si trace de ligne... */
{
fmtc(e, &ctxPdf->mPage, coul_rempl);
dynConcatSz(e, &ctxPdf->mPage, " rg ", DYN_LGNONE);
}
if(pointille > 0)
{
dynConcatSz(e, &ctxPdf->mPage, "[", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, Int64ToSz(e, pointille % 10, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, "] 0 d ", DYN_LGNONE);
}
else
dynConcatSz(e, &ctxPdf->mPage, "[] 0 d ", DYN_LGNONE);
//
if(epaisseur > 0)
{
dynConcatSz(e, &ctxPdf->mPage, Int64ToSz(e, epaisseur % 10, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, " w ", DYN_LGNONE);
}
//
if(type == 'L')
{
fmt2(e, &ctxPdf->mPage, x, y);
dynConcatSz(e, &ctxPdf->mPage, " m ", DYN_LGNONE);
fmt2(e, &ctxPdf->mPage, x + w, y + h);
dynConcatSz(e, &ctxPdf->mPage, " l S Q\r\n", DYN_LGNONE);
}
else
{
fmt4(e, &ctxPdf->mPage, x, y, w, h);
dynConcatSz(e, &ctxPdf->mPage, " re ", DYN_LGNONE);
if(type == 'R')
dynConcatSz(e, &ctxPdf->mPage, "f Q\r\n", DYN_LGNONE); /* remplissage */
else
if(type == 'D')
dynConcatSz(e, &ctxPdf->mPage, "B Q\r\n", DYN_LGNONE); /* cadre+remplissage */
else
dynConcatSz(e, &ctxPdf->mPage, "S Q\r\n", DYN_LGNONE); /* par defaut : cadre seul */
}
return cr;
}
WAPIDECL int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
{
int cr = TRUE;
/* x,y en mm, image numero <img> */
dynConcatSz(e, &ctxPdf->mPage, "q ", DYN_LGNONE);
dynField(e, &ctxPdf->mImg, &ctxPdf->mTmp1, img, 1, cFM, cVM, 1); // vm1 = larg (w) VM2 = haut (h) VM3 = bitmap 32bpp hexa RGB
dynConcat(e, &ctxPdf->mPage, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPage, " 0 0 ", DYN_LGNONE);
dynField(e, &ctxPdf->mImg, &ctxPdf->mTmp1, img, 2, cFM, cVM, 1); // vm1 = larg (w) VM2 = haut (h) VM3 = bitmap 32bpp hexa RGB
dynConcat(e, &ctxPdf->mPage, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPage, " ", DYN_LGNONE);
fmt2(e, &ctxPdf->mPage, x, y);
dynConcatSz(e, &ctxPdf->mPage, " cm /Img", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, Int64ToSz(e, img, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPage, " Do Q\r\n", DYN_LGNONE);
return cr;
}
WAPIDECL int pdfDeleteImage(env * e, modContextPdf * ctxPdf, long img)
{
// delete image number <img>, if 0 delete all
if(img > 0)
dynDel(e, &ctxPdf->mImg, img, DYN_NONE, cFM, DYN_NONE, 1);
else
dynSetLen(e, &ctxPdf->mImg, 0);
return TRUE;
}
//int pdfLoadImageRGB(env * e, Dynamic * pixel)
//{
// /* TODO png, jpeg,... en amont*/
// return TRUE;
//}
WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
{
long bpp, larg, haut, offset, par_ligne;
octet * p; /* pour simplifier le code... */
long i, j, pos, ind;
/* lecture fichier */
if(!fichier)
return FALSE;
if(fichier->type != VAR_DYNAMIC)
return FALSE;
// controle du bitmap avant memorisation
p = fichier->ptr;
if(p[0] != 'B' && p[1] != 'M')
return FALSE; /* pas un fichier .bmp */
//
bpp = p[28];
if(bpp != 24 && bpp != 32)
return FALSE; /* uniquement les fichiers bmp encodes en 24bpp ou 32bpp */
bpp = bpp >> 3;
/* */
offset = (p[11] << 8) + p[10];
larg = (p[19] << 8) + p[18];
haut = (p[23] << 8) + p[22];
par_ligne = larg * bpp; /* nb octets par ligne */
if((par_ligne & 3) != 0)
par_ligne += (4 - (par_ligne & 3));
/* la bitmap en hexa fera une taille de larg*haut*3*2 */
ind = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE) + 1;
dynStoreNumber(e, &ctxPdf->mImg, ind, 1, larg, cFM, cVM);
dynStoreNumber(e, &ctxPdf->mImg, ind, 2, haut, cFM, cVM);
dynConcatSz(e, &ctxPdf->mImg, sVM, 1);
// boucle sur chaque pixel
for(i = haut-1; i >= 0; i--)
for(j = 0; j < larg; j++)
{
pos = offset + j * bpp + i * par_ligne;
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos + 2]), 2);
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos + 1]), 2);
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos]), 2);
}
//printf("Image:\n%s\nlarg:%ld haut:%ld bpp:%ld ind:%ld parligne:%ld lenfichier:%lld\n", ctxPdf->mImg.mPtr, larg, haut, bpp, ind, par_ligne, fichier->mLg);
return TRUE;
}
WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic * lignes, long format)
{
// enchaine automatiquement les fonctions pour creer un pdf de type "listing" (log ou programme)
// police Courrier taille 9 en A4 =>
// paysage : 60 lignes 145 colonnes
// portrait : 87 lignes 99 colonnes
long nbLigPage, nbColPage;
if(format == PDFFMT_A4P)
{
// portrait
nbLigPage = 87;
nbColPage = 99;
}
else if(format == PDFFMT_A4L)
{
// paysage (Landscape)
nbLigPage = 60;
nbColPage = 145;
}
else
return FALSE; // format non pris en charge
//
long nbPage, nbLig;
dynErase(e, lignes, "\r");
nbLig = dynDcount(e, lignes, 10, DYN_NONE, DYN_NONE); // \n
if(nbLig == 0)
nbPage = 1;
else
nbPage = (nbLig - 1) / nbLigPage + 1;
//
dynLet(e, &ctxPdf->mTmp3, "Courier", DYN_LGNONE);
if( ! newPdf(e, ctxPdf, titre, nbPage, format, &ctxPdf->mTmp3))
return FALSE;
//
long iPage, iLigPage, iLigTotal = 1;
for(iPage = 1; iPage <= nbPage; iPage++)
{
dynConcatSz(e, &ctxPdf->mPage, "BT /F1 9 Tf ", 12); // Fonte 1 = Courier (/F1)
fmt2(e, &ctxPdf->mPage, ctxPdf->mLmarg, ctxPdf->mHaut - ctxPdf->mHmarg);
dynConcatSz(e, &ctxPdf->mPage, " Td 9 TL\r\n", DYN_LGNONE);
//
for(iLigPage = 1; iLigPage <= nbLigPage && iLigTotal <= nbLig; iLigPage++)
{
dynField(e, lignes, &ctxPdf->mTmp1, iLigTotal++, DYN_NONE, 10, DYN_NONE, 1);
if(ctxPdf->mTmp1.mLg > nbColPage)
dynSetLen(e, &ctxPdf->mTmp1, nbColPage);
pdfEchap(e, &ctxPdf->mTmp2, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPage, "(", 1);
dynConcatSz(e, &ctxPdf->mPage, ctxPdf->mTmp2.mPtr, ctxPdf->mTmp2.mLg);
dynConcatSz(e, &ctxPdf->mPage, ") '\r\n", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPage, "ET\r\n", DYN_LGNONE);
//
if( ! setPdfPage(e, ctxPdf, 1)) // compression forcee, mettre un param ?
return FALSE;
}
return endPdf(e, ctxPdf);
}
/* ******************************************************** */
+13 -12
View File
@@ -28,8 +28,10 @@
#include "langage.h"
#include "dynamic.h"
#define RAND_STATE_COUNT 624
#define RAND_PERIOD 397
enum {
RAND_STATE_COUNT = 624,
RAND_PERIOD = 397
};
typedef struct {
int error; // dernier code erreur specifique au module
@@ -84,13 +86,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -114,7 +115,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -129,7 +130,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
@@ -137,7 +138,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -152,7 +153,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -168,7 +169,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "setSeed", 7) == 0)
else if(modFnIs(e, "setSeed", 7))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -180,7 +181,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
if(param1 == NULL)
exc = EX_MODPARAM;
+395
View File
@@ -0,0 +1,395 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// TODO version windows
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#else
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
#include "dynamic.h"
#include "rep.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ******** PRIVATE ********************* */
static int GetInclude(env * e, Dynamic * line, Dynamic * includeFilename)
{
// check that the <line> is a include w statement. If not, return zero, else
// return in <includeFilename> the name of the include file
// separators are 9 and 32 (tab and space) and ";"" for the optional end of line comment
char * p = line->mPtr, * q;
while(*p && (*p == 9 || *p == 32)) p++;
if(*p++ != 'i') return 0;
if(*p++ != 'n') return 0;
if(*p++ != 'c') return 0;
if(*p++ != 'l') return 0;
if(*p++ != 'u') return 0;
if(*p++ != 'd') return 0;
if(*p++ != 'e') return 0;
if(*p != 9 && *p != 32) return 0;
p++;
while(*p && (*p == 9 || *p == 32)) p++;
if(*p != '\'' && *p != '"') return 0;
q = p + 1; // *p is the first char of include filename , including ' or ", and that chra must bi found at the end of the file
while(*q && (*q != *p)) q++;
if(*q != *p) return 0; // *q must be the same ' or " that begins filename
long lg = q - p - 1;
if(lg < 1) return 0;
dynLet(e, includeFilename, p + 1, lg);
dynSetLen(e, includeFilename, lg); // to be sure that \0 ends the filename
return 1;
}
/* ******** PUBLIC ********************* */
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount)
{
if(!e || !directory || !fileFound || !fileFoundCount || !duplicateCount)
return 0; // error
//
// non-recursive method : scan <path> and save each directory in <directory>'s fields. Then scan each directory and save subdirectories, in <directory>'s fields, at the end.
// And so on for each newly saved subdirectories. Finally, <directory>'s fields will contain all directories and subdirectories within <path>
// if <path> is null, <directory> already contains the list of directory to scan, else directory is setup with the directory tree.
// if <fileToSearch> is not null : <fileFound> is filled (within fields) with the full path name of each file name found.
// <fileFoundCount> contains the number of times the file was found (i.e. <fileFound> field's number)
// if <fileToSearch> is equal to "*" : means to check for duplicate files within the whole directory tree (<duplicateCount> gives the number of it),
// and so <fileFound> will contains all filenames (without path)
//
if(path)
dynSetAsSz(e, directory, (char *)path);
long nb = dynDcount(e, directory, cFM, DYN_NONE, DYN_NONE), done = 0;
//
#ifdef UNIX
DIR * dir = NULL;
struct dirent * entry = NULL;
#else
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
#endif
//
Dynamic workPath;
dynInit(e, &workPath, DYN_LGMIN);
//
*duplicateCount = 0;
*fileFoundCount = 0;
if(fileToSearch)
dynSetLen(e, fileFound, 0);
//
while(nb > done)
{
long newNb = nb;
for(long ind = done + 1; ind <= nb; ind++)
{
//dynExtractField(e, directory, ind, &workPath);
dynField(e, directory, &workPath, ind, DYN_NONE, cFM, DYN_NONE, 1);
// read each entry in directory and save subdirectory name (full path)
// TODO !? => check that workPath hasn't yet been scanned (e.g. directory link with circular reference)
#ifdef UNIX
if((dir = opendir(workPath.mPtr)) == NULL)
{
// continue to next item (no access right for example for this directory, etc.)
//dynFree(e, &workPath);
//return 0;
continue;
}
while ((entry = readdir(dir)) != NULL)
{
if(path)
{
if(entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
{
newNb++;
dynStore(e, directory, newNb, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '/')
dynConcatSz(e, directory, "/", 1);
dynConcatSz(e, directory, entry->d_name, DYN_LGNONE);
}
}
// check "regular" files (DT_REG si linux specific)
if(fileToSearch)
{
if(entry->d_type == DT_REG && *fileToSearch == '*')
{
long pos = dynLocateSz(e, fileFound, entry->d_name, cFM, DYN_NONE, DYN_NONE);
if(pos > 0)
(*duplicateCount)++; // duplicate found
else
{
(*fileFoundCount)++;
dynStoreSz(e, fileFound, *fileFoundCount, DYN_NONE, entry->d_name, DYN_LGNONE, cFM, DYN_NONE); // duplicate checking doesn't take care of the file's path
}
}
else if(entry->d_type == DT_REG && strcmp(entry->d_name, fileToSearch) == 0)
{
// file found
(*fileFoundCount)++; // found, save file's directory
dynStore(e, fileFound, *fileFoundCount, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '/')
dynConcatSz(e, fileFound, "/", 1);
dynConcatSz(e, fileFound, entry->d_name, DYN_LGNONE);
}
}
}
closedir(dir);
// end readdir
#else
dynConcatSz(e, &workPath, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(workPath.mPtr, &FindFileData)) == INVALID_HANDLE_VALUE)
{
// continue to next item (no access right for example for this directory, etc.)
//dynFree(e, &workPath);
//return 0;
continue;
}
dynSetLen(e, &workPath, workPath.mLg - 2); // enlever \* mis a la fin...
for(int cr = -1;cr != 0;)
{
if(path)
{
if((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
{
newNb++;
dynStore(e, directory, newNb, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '\\')
dynConcatSz(e, directory, "\\", 1);
dynConcatSz(e, directory, FindFileData.cFileName, DYN_LGNONE);
}
}
// check "regular" files (DT_REG si linux specific)
if(fileToSearch)
{
if( !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) &&
!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
if( *fileToSearch == '*')
{
long pos = dynLocateSz(e, fileFound, FindFileData.cFileName, cFM, DYN_NONE, DYN_NONE);
if(pos > 0)
(*duplicateCount)++; // duplicate found
else
{
(*fileFoundCount)++;
dynStoreSz(e, fileFound, *fileFoundCount, DYN_NONE, FindFileData.cFileName, DYN_LGNONE, cFM, DYN_NONE); // duplicate checking doesn't take care of the file's path
}
}
else if(strcmp(FindFileData.cFileName, fileToSearch) == 0)
{
// file found
(*fileFoundCount)++; // found, save file's directory
dynStore(e, fileFound, *fileFoundCount, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '\\')
dynConcatSz(e, fileFound, "\\", 1);
dynConcatSz(e, fileFound, FindFileData.cFileName, DYN_LGNONE);
}
}
//
cr = FindNextFile(hFind, &FindFileData);
}
FindClose(hFind);
#endif
}
done = nb;
nb = newNb;
}
dynFree(e, &workPath);
return 1;
}
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta)
{
int cr = 0;
char cLF = 10;
char sLF[2] = {"\n"};
char sCR[2] = {"\r"};
dynSetLen(e, source, 0);
dynSetLen(e, meta, 0);
//
Dynamic fileFound, line, include, filenameFound;
dynInit(e, &fileFound, DYN_LGMIN);
dynInit(e, &line, DYN_LGMIN);
dynInit(e, &include, DYN_LGMIN);
dynInit(e, &filenameFound, DYN_LGMIN);
//
long fileCount, dup;
for(;;)
{
if( ScanDirectory(e, NULL, directory, filename, &fileFound, &fileCount, &dup) != 1)
{
cr = 1;
break;
}
if(fileCount != 1)
{
cr = 2;
break;
}
if(dynRead(e, source, fileFound.mPtr) != DYN_OK)
{
cr = 3;
break;
}
dynErase(e, source, sCR);
//
long treeLevel = 1, currentLevel = 1, level = 0, nbMeta = 1;
dynStoreSz(e, meta, META_GLOBAL_LN, DYN_NONE, "00000001", 8, cFM, DYN_NONE);
dynStoreSz(e, meta, META_FILENAME, DYN_NONE, fileFound.mPtr, DYN_LGNONE, cFM, DYN_NONE);
dynStoreSz(e, meta, META_LOCAL_LN, DYN_NONE, "1", DYN_LGNONE, cFM, DYN_NONE);
dynStoreNumber(e, meta, META_LEVEL, DYN_NONE, currentLevel, cFM, DYN_NONE);
dynStoreSz(e, meta, META_FILETREE, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
// foreach source line
long numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE);
long numLine = 1;
for( ;numLine <= numberOfLines; )
{
dynField(e, source, &line, numLine, DYN_NONE, cLF, DYN_NONE, 1);
numLine++;
if(GetInclude(e, &line, &include))
{
if(ScanDirectory(e, NULL, directory, include.mPtr, &fileFound, &fileCount, &dup))
{
if(fileCount == 1)
{
// memo include file tree to avoid cyclic includes and get meta data
// 2 memos : one for call tree, and one for the map of files/number of lines
// call tree =>
// meta<5> = file tree, multi-valued filenames (temporary, during GetSource)
// meta data =>
// meta<1> = beginning line number, global
// meta<2> = filename
// meta<3> = local line number
// meta<4> = level
//
// if filename already presents in file tree, error (ignore include)
dynRead(e, &include, fileFound.mPtr);
dynField(e, &fileFound, &filenameFound, dynDcount(e, &fileFound, e->path_sep[0], DYN_NONE, DYN_NONE), DYN_NONE, e->path_sep[0], DYN_NONE, 1); // extract filename from full path
if(dynLocateSz(e, meta, filenameFound.mPtr, cVM, META_FILETREE, cFM) > 0)
{
cr = 4;
break;
}
// insert include file after include's line
if(include.mLg == 0) // don't insert empty file (else, local line number calculus wouldn't be correct), add one space instead
{
dynLet(e, &include, " ", 1);
}
else
{
dynErase(e, &include, sCR);
if(include.mPtr[include.mLg - 1] != cLF)
dynConcatSz(e, &include, sLF, 1); // add empty final line if there's not, else meta would have double same global line (if last line is include's line)
}
//
dynIns(e, source, numLine, DYN_NONE, &include, cLF, DYN_NONE);
long nbInclude = dynDcount(e, &include, cLF, DYN_NONE, DYN_NONE);
numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE); // extending scope
//
// put in <include> the line number formatted 00000000 and split current block in three
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
long pos = abs(dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM));
dynIns(e, meta, META_GLOBAL_LN, pos, &include, cFM, cVM);
dynIns(e, meta, META_FILENAME, pos, &fileFound, cFM, cVM);
dynInsSz(e, meta, META_LOCAL_LN, pos, "1", 1, cFM, cVM);
level = dynFieldAsNumber(e, meta, META_LEVEL, pos - 1, cFM, cVM);
dynInsNumber(e, meta, META_LEVEL, pos, level + 1, cFM, cVM);
currentLevel = level + 1;
//
dynField(e, meta, &include, 2, pos - 1, cFM, cVM, 1);
dynIns(e, meta, META_FILENAME, pos + 1, &include, cFM, cVM);
dynFmtNumber(e, numLine + nbInclude, &include, 'R', '0', 8);
dynIns(e, meta, META_GLOBAL_LN, pos + 1, &include, cFM, cVM);
long global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, pos - 1, cFM, cVM);
long local = dynFieldAsNumber(e, meta, META_LOCAL_LN, pos - 1, cFM, cVM);
dynInsNumber(e, meta, META_LOCAL_LN, pos + 1, numLine - global + local, cFM, cVM);
dynInsNumber(e, meta, META_LEVEL, pos + 1, level, cFM, cVM);
//
// adjust starting line of next blocks
nbMeta = dynDcount(e, meta, cVM, META_FILENAME, cFM);
for(long cpt = pos + 2; cpt <= nbMeta; cpt++)
{
global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, cpt, cFM, cVM);
dynFmtNumber(e, global + nbInclude, &include, 'R', '0', 8);
dynStore(e, meta, META_GLOBAL_LN, cpt, &include, cFM, cVM);
}
//
dynStore(e, meta, META_FILETREE, ++treeLevel, &filenameFound, cFM, cVM);
}
else
{
cr = 5; // if fileCount <> 1, error (multiple included include not autorized, or not found when filename includes dot or path separator char)
break;
}
}
else
{
cr = 6; // if error while searching for the include file, error
break;
}
}
// delete last file in call tree when changing of file
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
long pos = dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM);
if(pos < 0)
pos = abs(pos) - 1;
if(pos > nbMeta)
pos = nbMeta;
level = dynFieldAsNumber(e, meta, META_LEVEL, pos, cFM, cVM);
if(level < currentLevel)
dynDel(e, meta, META_FILETREE, treeLevel--, cFM, cVM, 1);
currentLevel = level;
}
dynDel(e, meta, META_FILETREE, DYN_NONE, cFM, DYN_NONE, 1);
break;
}
//
dynFree(e, &fileFound);
dynFree(e, &line);
dynFree(e, &include);
dynFree(e, &filenameFound);
return cr;
}
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine)
{
indice = (indice - 1) * META_NB;
dynFmtNumber(e, lineNumber, fileFound, 'R', '0', 8);
long pos = dynSortLocateSz(e, meta, fileFound->mPtr, cVM, DYN_SORT_ASC, indice + META_GLOBAL_LN, cFM);
if(pos < 0)
pos = abs(pos) - 1;
//
*ficLine = lineNumber - dynFieldAsNumber(e, meta, indice + META_GLOBAL_LN, pos, cFM, cVM) + dynFieldAsNumber(e, meta, indice + META_LOCAL_LN, pos, cFM, cVM);
dynField(e, meta, fileFound, indice + META_FILENAME, pos, cFM, cVM, 1);
}
+44
View File
@@ -0,0 +1,44 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifndef REP_H
#define REP_H
#include "apidecl.h"
enum {
META_GLOBAL_LN = 1,
META_FILENAME = 2,
META_LOCAL_LN = 3,
META_LEVEL = 4,
META_FILETREE = 5,
META_WSRC = 5,
META_NB = 5
};
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount);
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta);
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine);
/* ********************************************** */
#endif
+73
View File
@@ -0,0 +1,73 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef WINLIB
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#else
#include <windows.h>
#endif
#include "langage.h"
#ifdef WINLIB
typedef int key_t;
#endif
/* codes a passer a la fonction setError */
enum {
EXMOD_BUFFER_INIT = 1,
EXMOD_BUFFER_WRITE = 2
};
typedef struct {
// proprietaire
key_t cle;
char nom[24]; // 23 cars + \0
long taille;
var * buffer;
#ifndef WINLIB
int handle;
int semId;
#else
HANDLE handle;
char semDesti[25]; // 23 cars + '#' + \0 (different desti sinon ko sous windows)
HANDLE newProcess; // writer: handle process creee en SUSPEND, reader : handle passe en arg et convertit en num
#endif
// destinataire
char desti[24]; // 23 cars + \0
// message lu/ecrit
var * message;
} modContextShm;
WAPIDECL void initShm(env * e, modContextShm * ctx);
WAPIDECL void freeShm(env * e, modContextShm * ctx);
WAPIDECL long readShm(env * e, modContextShm * ctx);
WAPIDECL long writeShm(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx);
+174
View File
@@ -0,0 +1,174 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "hashtable.h"
#include "shm.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextShm cs;
} modEtat;
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
var * prog;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_PROG), &prog);
// maj ctx avec _prog et taille
*((ent64 *)(p_etat->cs.nom)) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 1) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 2) = 0;
if(prog && prog->type == VAR_DYNAMIC && prog->mLg < 24)
strncpy(p_etat->cs.nom, prog->mPtr, prog->mLg);
p_etat->cs.taille = 4000;
//
initShm(e, &p_etat->cs);
}
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
freeShm(e, &p_etat->cs);
//*** FIN du code specifique ici
memfree(e, p_etat);
}
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(!param1)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
p_etat->cs.message = param1;
exc = setError(p_etat, readShm(e, &p_etat->cs));
// param1 vide si rien a lire
}
}
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
if(!param1 || !param2)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
*((ent64 *)(p_etat->cs.desti)) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 1) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 2) = 0;
if(param1->mLg < 24)
strncpy(p_etat->cs.desti, param1->mPtr, param1->mLg);
p_etat->cs.message = param2;
exc = setError(p_etat, writeShm(e, &p_etat->cs));
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
}
//
return exc;
}
/* **************************************************************************************************** */
+491
View File
@@ -0,0 +1,491 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "shm.h"
#include "buffer.h"
#include "dynamic.h"
#include <errno.h>
#ifndef WINLIB
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
enum {
NBSEM = 1
};
/* ****** PRIVATE ************************ */
static key_t Hash32(const char * cle, int lg)
{
// lg multiple de 4 et > 0
// cle est une zone memoire de lg cars
ent64 k, h = 0;
if(lg > 0 && (lg % 4 == 0))
{
h = *(int *)cle;
for(int i = 0; i < lg; )
{
k = (ent64)cle[i++];
k |= ((ent64)cle[i++]) << 8;
k |= ((ent64)cle[i++]) << 16;
k |= ((ent64)cle[i++]) << 24;
k *= 0xcc9e2d51;
k = (k << 15) | (k >> 17); // 32 - 15
k *= 0x1b873593;
h ^= k;
h = (h << 13) | (h >> 19); // 32 - 13
h = h * 5 + 0xe6546b64;
}
}
h ^= lg;
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return (key_t)h;
}
/* ****** PUBLIC ************************ */
WAPIDECL void initShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
ctx->buffer = NULL;
ctx->handle = -1;
ctx->semId = -1;
// creer la sharedmemory du process, pour lecture
// ne pas controler la taille, sera fait par 'shmget'
// calculer la cle a partir du nom du prog (ctx->nom)
ctx->cle = Hash32(ctx->nom, 24); // chaine de 23 cars max + \0 de fin
// securite : supprimer un eventuel reliquat d'un ancien shm ? Faire un appel externe pas systematique, que le createur, (ou mettre un flag)
//shmctl(ctx->cle, IPC_RMID, NULL);
// creer le buffer
ctx->handle = shmget(ctx->cle, ctx->taille, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(ctx->handle < 0)
return; // erreur creation sharedmemory
// lire le pointeur
ctx->buffer = (var *)shmat(ctx->handle, NULL, 0);
if(ctx->buffer == (var *)(-1))
{
shmctl(ctx->handle, IPC_RMID, NULL);
ctx->buffer = NULL;
ctx->handle = -1;
return; // erreur recup pointeur
}
// creer le semaphore pour les writers
ctx->semId = semget(ctx->cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(ctx->semId < 0)
{
freeShm(e, ctx); // erreur
return;
}
// init semaphore
unsigned short table[NBSEM];
table[0] = 1;
if(semctl(ctx->semId, 0, SETALL, table) < 0)
{
freeShm(e, ctx); // erreur
return;
}
#else
ctx->buffer = NULL;
ctx->handle = NULL;
strncpy(ctx->semDesti, ctx->desti, 24);
ctx->semDesti[24] = 0;
ctx->semDesti[strlen(ctx->desti)] = '#';
// creer la sharedmemory du process, pour lecture
// ne pas controler la taille, sera fait par 'CreateFileMapping'
// la cle est directement le nom
// creer le buffer
ctx->handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->taille, ctx->nom); // NULL si ko, attention au \0 de fin de ctx->nom
if( ! ctx->handle)
return; // erreur creation sharedmemory
ctx->buffer = (var *)MapViewOfFile(ctx->handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! ctx->buffer)
{
CloseHandle(ctx->handle);
ctx->buffer = NULL;
ctx->handle = NULL;
return; // erreur recup pointeur
}
#endif
ctx->buffer->type = VAR_BUFFER;
ctx->buffer->lgmax = ctx->taille - sizeof(var);
ctx->buffer->read = 0;
ctx->buffer->write = 0;
ctx->buffer->ptr = NULL; // NULL signifie que le contenu est a la suite de l'entete de la variable (utilise uniquement ici avec les IPC)
}
WAPIDECL void freeShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
if(ctx->buffer)
shmdt(ctx->buffer);
if(ctx->handle >= 0)
shmctl(ctx->handle, IPC_RMID, NULL);
if(ctx->semId >= 0)
semctl(ctx->semId, IPC_RMID, 0);
ctx->buffer = NULL;
ctx->handle = -1;
ctx->semId = -1;
#else
if(ctx->buffer)
UnmapViewOfFile(ctx->buffer);
if(ctx->handle >= 0)
CloseHandle(ctx->handle); // verif que bien detruit
ctx->buffer = NULL;
ctx->handle = NULL;
#endif
}
WAPIDECL long readShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
if( ! ctx->buffer || ctx->handle < 0)
return EXMOD_BUFFER_INIT;
#else
if( ! ctx->buffer || ! ctx->handle)
return EXMOD_BUFFER_INIT;
#endif
buffer_read(e, ctx->buffer, ctx->message);
// e->exception != OK si exception en lecture (que EX_MEM) ! vide si rien a lire (Dynamic)
return e->exception;
}
WAPIDECL long writeShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
// calculer la cle a partir du nom du prog (ctx->nom)
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au buffer
int handle = shmget(cle, 0, 0);
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
var * buffer = (var *)shmat(handle, NULL, 0);
if(buffer == (var *)(-1))
return EXMOD_BUFFER_WRITE; // seul le ptr se libere
// prendre le verrou (semaphore) pour ecrire, avec attente
int semId = semget(cle, NBSEM, 0);
if(semId < 0)
{
shmdt(buffer);
return EXMOD_BUFFER_WRITE;
}
struct sembuf bufw;
bufw.sem_num = 0;
bufw.sem_op = -1; // prendre
bufw.sem_flg = SEM_UNDO; // | IPC_NOWAIT ?
if(semop(semId, &bufw, 1) < 0)
{
shmdt(buffer);
return EXMOD_BUFFER_WRITE;
}
// EcrireBuffer
buffer_write(e, buffer, ctx->message);
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
// liberer le verrou
bufw.sem_op = 1; // liberer
semop(semId, &bufw, 1);
// ne liberer que le ptr sous unix
shmdt(buffer);
#else
// la cle est directement le destinataire
HANDLE handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, ctx->desti); // attention au \0 de fin
if( ! handle)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
var * buffer = (var *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! buffer)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// prendre le verrou (semaphore) pour ecrire, avec attente
HANDLE hSem = CreateSemaphore(NULL, 1, 1, ctx->semDesti); // NULL si erreur
if( ! hSem)
{
UnmapViewOfFile(buffer);
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
if(WaitForSingleObject(hSem, 0) != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur ; 0 = timeout en secondes
{
ReleaseSemaphore(hSem, 1, NULL);
UnmapViewOfFile(buffer);
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// EcrireBuffer
buffer_write(e, buffer, ctx->message);
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
// liberer le verrou
ReleaseSemaphore(hSem, 1, NULL);
// liberations
UnmapViewOfFile(buffer);
CloseHandle(handle);
#endif
return e->exception;
}
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, ctx->message->lg + sizeLg, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// ne liberer que le ptr sous unix
shmdt(data);
#else
// la cle est directement le destinataire
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->message->lg + sizeLg, ctx->desti); // attention au \0 de fin
if( ! handle)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// dupliquer le HANDLE sur le mapping
HANDLE dup = NULL;
if( ! DuplicateHandle(GetCurrentProcess(), handle, ctx->newProcess, &dup, 0, FALSE, DUPLICATE_SAME_ACCESS))// FALSE : le handle dupliqué n’a pas besoin d’être héritable
e->exception = EXMOD_BUFFER_WRITE;
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, 0, 0); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// ne liberer que le ptr sous unix
shmdt(data);
shmctl(handle, IPC_RMID, NULL);
#else
// lire le pointeur, a partir du handle lu de la ligne de commande
HANDLE handle = ctx->newProcess;
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
#ifndef WINLIB
WAPIDECL int OpenLock(env * e, const char * name)
{
key_t cle = Hash32(name, 24); // chaine de 23 cars max + \0 de fin
int semId = semget(cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666);
if(semId < 0)
{
if(errno != EEXIST)
return -1; // erreur
// deja cree, ok
semId = semget(cle, NBSEM, 0);
if(semId < 0)
{
return -1; // erreur
}
}
else
{
// init semaphore
unsigned short table[NBSEM];
table[0] = 1;
if(semctl(semId, 0, SETALL, table) < 0)
{
semctl(semId, IPC_RMID, 0);
return -1; // erreur
}
}
return semId; // >=0 : ok
}
#else
WAPIDECL HANDLE OpenLock(env * e, const char * name)
{
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
char fullName[40] = {0};
if(strlen(name) > 23)
return NULL; // nom trop long
//
strcpy(fullName, "Global\\");
strcat(fullName, name);
HANDLE hSem = CreateSemaphore(&sa, 1, 1, fullName); // 1 = valeur initiale du semaphore ; 1 = valeur max du semaphore ; nom du semaphore (unique)
if( ! hSem)
return NULL; // erreur (si existe, ne passe pas ici, hSem est renseigne avec le sem existant) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur, dans ce cas hSem n'est pas NULL
else
return hSem;
}
#endif
#ifndef WINLIB
WAPIDECL void CloseLock(env * e, int semId)
{
if(semId >= 0)
semctl(semId, IPC_RMID, 0);
}
#else
WAPIDECL void CloseLock(env * e, HANDLE hSem)
{
CloseHandle(hSem);
}
#endif
#ifndef WINLIB
WAPIDECL int SetLock(env * e, int semId, int milliSec)
{
// prendre le verrou (semaphore) pour ecrire, avec attente
struct sembuf bufw;
struct timespec ts;
ts.tv_sec = milliSec / 1000;
ts.tv_nsec = (milliSec % 1000) * 1000000; // xxx ms
bufw.sem_num = 0;
bufw.sem_op = -1; // prendre
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
if(semop(semId, &bufw, 1) < 0)
{
if(errno != EAGAIN)
return -1; // erreur : semaphore ko
// semaphore pris : attendre et reessayer une fois
nanosleep(&ts, NULL);
if(semop(semId, &bufw, 1) < 0)
{
if(errno != EAGAIN)
return -1; // erreur : semaphore ko
return 0; // sortie en timeout cette fois
}
}
return 1; // ok
}
#else
WAPIDECL int SetLock(env * e, HANDLE hSem, int milliSec)
{
int cr = WaitForSingleObject(hSem, milliSec);
if( cr != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur
{
// semaphore pris : attendre ?
if(cr != WAIT_TIMEOUT)
return -1; // erreur
// sortie en time out, semaphore pris, attendre ?
return 0;
}
return 1;
}
#endif
#ifndef WINLIB
WAPIDECL void UnsetLock(env * e, int semId)
{
// liberer le verrou
struct sembuf bufw;
bufw.sem_num = 0;
bufw.sem_op = 1; // liberer
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
semop(semId, &bufw, 1);
}
#else
WAPIDECL void UnsetLock(env * e, HANDLE hSem)
{
// liberer le semaphore
ReleaseSemaphore(hSem, 1, NULL);
}
#endif
+78
View File
@@ -0,0 +1,78 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "langage.h"
#ifndef WINLIB
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#include <unistd.h>
typedef int Socket;
typedef struct pollfd * wPoll;
#else
#include "winsock2.h" // link avec ws2_32.lib
#include <windows.h>
typedef SOCKET Socket;
typedef LPWSAPOLLFD wPoll;
#endif
/* codes a passer a la fonction setError */
enum {
EXMOD_SOCKET_ERROR = -1,
EXMOD_SOCKET_OK = 0,
EXMOD_SOCKET_INIT = 1,
SOCKET_LISTEN_MAX = 10
};
typedef struct {
var * listSocket; // contient le tableau de pollfd/WSAPOLLFD encapsule dans un dynamic
int nbSocket; // nombre d'elements dans le tableau de pollfd
wPoll poll; // pointeur vers le tableau de pollfd/WSAPOLLFD
#ifdef UNIX
sigset_t mOldBlockSig,mBlockSig; /* gestion des signaux sur socket serveur en ecoute (utile ?) */
#endif
} modContextSocket;
WAPIDECL void initSock(env * e, modContextSocket * ctx);
WAPIDECL void freeSock(env * e, modContextSocket * ctx);
WAPIDECL Socket NewSocket();
WAPIDECL int SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port);
WAPIDECL Socket AcceptClientSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL int SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * server);
WAPIDECL int AddSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL void DelSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL int WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL int WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs);
WAPIDECL void FreeSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL int GetSocketError();
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data);
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data);
+78 -73
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -29,32 +29,33 @@
#include <errno.h>
#ifdef UNIX
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#else
#include "windows.h"
#include "winsock2.h"
#include "windows.h"
#endif
#include "langage.h"
#include "dynamic.h"
#include "sock.h"
typedef struct {
int error; /* dernier code erreur specifique au module */
//***
long mSocket; /* socket en cours */
int mServeur; /* 0 socket serveur mere en ecoute, 1 socket serveur fille connectee a un client, 2 socket client */
modContextSocket cs;
// TODO a enlever quand sock_lib.c ok
int mSocket,mServeur;
#ifdef UNIX
sigset_t mOldBlockSig,mBlockSig; /* gestion des signaux sur socket serveur en ecoute */
#endif
// TODO : gerer plusieurs sockets (serveur ? client ?)
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
} modEtat;
static int setError(modEtat * p, int err)
{
@@ -63,13 +64,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -77,16 +77,24 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
// init/end/vers/error sont obligatoires pour tout module
// fonction createServer, arret
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -97,48 +105,45 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
p_etat->mSocket = 0;
p_etat->mServeur = 0;
initSock(e, &p_etat->cs);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
//***
if(p_etat->mSocket > 0)
close(p_etat->mSocket);
freeSock(e, &p_etat->cs);
//***
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "server", 6) == 0)
else if(modFnIs(e, "server", 6))
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
@@ -147,8 +152,8 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
return exc;
}
// param<1> = numero de port ; TODO : mettre une VAR_NUMBER ??
long port = dynToNum(e, param, 0, 5);
if(param->mInternal == DYN_ERR)
long port = dynToNum(e, param1, 0, 5);
if(param1->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
@@ -200,7 +205,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat->mSocket = 0;
return exc;
}
// linger n'impacte QUE le close de la socket
// linger n'impacte QUE le close de la socket, a voir si vraiment utile avec shutdown...
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
@@ -244,27 +249,27 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "connect", 7) == 0)
else if(modFnIs(e, "connect", 7))
{
char ** tParam;
/* connexion a un serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(dynDcount(e, param, cFM, DYN_NONE, DYN_NONE) < 2)
else if(dynDcount(e, param1, cFM, DYN_NONE, DYN_NONE) < 2)
exc = EX_MODPARAM; /* erreur */
else
{
// param<1> = host (nom ou ip)
// param<2> = port
// decouper en 2 chaines Comm
tParam = dynToTabPtr(e, param, cFM);
tParam = dynToTabPtr(e, param1, cFM);
if(tParam == NULL)
exc = EX_MODPARAM; /* erreur */
}
if(exc != OK)
return exc;
long port = atoi(tParam[1]);
if(param->mInternal == DYN_ERR)
if(param1->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
@@ -317,7 +322,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat->mSocket = 0;
return exc;
}
// linger n'impacte QUE le close de la socket
// linger n'impacte QUE le close de la socket, a voir si vraiment utile avec shutdown...
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
@@ -347,24 +352,24 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "arret", 5) == 0)
else if(modFnIs(e, "arret", 5))
{
/* arret connexion cliente ou serveur */
if(p_etat != NULL)
{
shutdown(p_etat->mSocket, 2);
shutdown(p_etat->mSocket, 2); // 2 = RDWR sous Unix, shutdown permet de se passer de SO_LINGER !?
close(p_etat->mSocket);
p_etat->mSocket = 0;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "attente", 7) == 0)
else if(modFnIs(e, "attente", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_NUMBER)
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
@@ -372,8 +377,8 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
struct timeval delai;
long cr;
// attend une activite sur la socket, timeOut en 1/10 de sec.
delai.tv_sec = param->num / NUM_FACTEUR; // x sec
delai.tv_usec = (param->num % NUM_FACTEUR) * 10; // y µsec
delai.tv_sec = param1->num / NUM_FACTEUR; // x sec
delai.tv_usec = (param1->num % NUM_FACTEUR) * 10; // y µsec
FD_ZERO(&masque);
FD_SET(p_etat->mSocket, &masque);
//
@@ -397,22 +402,22 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
cr = FD_ISSET(p_etat->mSocket, &masque);
}
if(cr > 0)
param->num = NUM_UN; /* ok pour lire */
param1->num = NUM_UN; /* ok pour lire */
else
param->num = NUM_ZERO; /* pas de donnees */
param1->num = NUM_ZERO; /* pas de donnees */
// si cr > 0 : ok pour continuer et lire la socket
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
long nblu = 0, arg = 1, flagInProgress = 0, pas = 16000, would_block;
/* lecture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
@@ -421,17 +426,17 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) necessaire quand la longueur n'est pas connue (sinon lire sur la longueur et laisser(?) la socket bloquante) */
#endif
dynSetLen(e, param, 0);
dynSetLen(e, param1, 0);
do
{
if(!dynCtrl(e, param, param->mLg + pas, 1)) /* avec recopie */
if(!dynCtrl(e, param1, param1->mLg + pas, 1)) /* avec recopie */
{
exc = setError(p_etat, 1);
break;
}
would_block = 0;
while((nblu = read(p_etat->mSocket, param->mPtr + param->mLg, pas)) < 0 && errno == EWOULDBLOCK /* WouldBlock = 11 */
&& (param->mLg == 0 || flagInProgress) && (++would_block) < 100)
while((nblu = read(p_etat->mSocket, param1->mPtr + param1->mLg, pas)) < 0 && errno == EWOULDBLOCK /* WouldBlock = 11 */
&& (param1->mLg == 0 || flagInProgress) && (++would_block) < 100)
#ifdef UNIX
usleep(10000); /* attente de 10 ms entre chaque appel, maxi 100 fois (a garder ?) */
#else
@@ -440,29 +445,29 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
if(errno == EINPROGRESS) /* 115 */
flagInProgress = 1; /* indique un envoi en plusieurs parties : ne plus sortir quand getLen # 0 car lecture pas finie ! */
if(nblu > 0)
dynSetLen(e, param, param->mLg + nblu);
dynSetLen(e, param1, param1->mLg + nblu);
/* */
} while (nblu > 0);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "set", 3))
{
long nb , pos = 0, lg, would_block;
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
lg = param->mLg;
lg = param1->mLg;
while(lg > 0)
{
would_block = 0;
while((nb = write(p_etat->mSocket, param->mPtr + pos, lg)) < 0 && errno == EWOULDBLOCK
while((nb = write(p_etat->mSocket, param1->mPtr + pos, lg)) < 0 && errno == EWOULDBLOCK
&& (++would_block) < 100)
#ifdef UNIX
usleep(10000); /* attente 10 ms entre chaque appel, maxi 100 fois (a garder ?) */
@@ -481,14 +486,14 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "accept", 6) == 0)
else if(modFnIs(e, "accept", 6))
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_NUMBER)
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
@@ -496,9 +501,9 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
unsigned int size_addr_cnx = sizeof(addr_cnx);
int sock;
if((sock = accept(p_etat->mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
param->num = sock * NUM_FACTEUR; /* nouvelle requete entrante : renvoie num socket */
param1->num = sock * NUM_FACTEUR; /* nouvelle requete entrante : renvoie num socket */
else
param->num = NUM_ZERO; /* pas de nouvelle connexion entrante finalement */
param1->num = NUM_ZERO; /* pas de nouvelle connexion entrante finalement */
}
}
/* ----------------------------------------------------------------------------------------------- */
+360
View File
@@ -0,0 +1,360 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "sock.h"
#include "dynamic.h"
#include <errno.h>
#ifdef WINLIB
#include <ws2tcpip.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/* ****** PRIVATE ************************ */
/* ****** PUBLIC ************************ */
WAPIDECL void initSock(env * e, modContextSocket * ctx)
{
dynSetLen(e, ctx->listSocket, 0); // raz liste sockets
//
#ifdef WINLIB
WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);
#endif
}
WAPIDECL void freeSock(env * e, modContextSocket * ctx)
{
// TODO fermer les sockets ouvertes
#ifdef WINLIB
WSACleanup();
#endif
}
WAPIDECL Socket NewSocket()
{
#ifdef WINLIB
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
int iOptVal = 0;
int iOptLen = sizeof(int);
u_long block_mode = 1; // 1 = non-bloquant, 0 = bloquant
#else
int sockopt = 1;
#endif
struct linger l_s; /* Structure pour setsockopt */
Socket sock;
/* */
#ifndef WINLIB
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
#else
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
#endif
return EXMOD_SOCKET_ERROR;
/* */
#ifndef WINLIB
ioctl(sock, FIONBIO, &sockopt); /* socket non bloquant (sys/ioctl.h) */
// autre maniere
//int flags = fcntl(fd, F_GETFL, 0);
//if (flags == -1) return -1;
//if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) return -1;
#else
ioctlsocket(sock, FIONBIO, &block_mode);
#endif
/* */
/* voir ici https://learn.microsoft.com/fr-fr/windows/win32/api/winsock/nf-winsock-setsockopt pour les parametres a passer selon l'option */
#ifndef WINLIB
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
#else
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen)) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
#endif
{
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
}
/* linger n'impacte QUE le close de la socket */
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
{
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
}
/* autres options ? */
return sock;
}
WAPIDECL int SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port)
{
struct sockaddr_in addr;
//
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
#ifndef WINLIB
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
#else
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == EXMOD_SOCKET_ERROR)
#endif
{
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
}
#ifndef WINLIB
if(listen(sock, SOCKET_LISTEN_MAX) < 0)
#else
if(listen(sock, SOCKET_LISTEN_MAX) == EXMOD_SOCKET_ERROR)
#endif
{
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
}
return EXMOD_SOCKET_OK;
}
WAPIDECL Socket AcceptClientSocket(env * e, modContextSocket * ctx, Socket sock)
{
struct sockaddr_in addr_cnx;
unsigned int size_addr_cnx = sizeof(addr_cnx);
Socket clientSock;
#ifndef WINLIB
if((clientSock = accept(sock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
#else
if((clientSock = accept(sock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) != INVALID_SOCKET)
#endif
return clientSock;
else
return EXMOD_SOCKET_ERROR;
}
WAPIDECL int SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * server)
{
struct sockaddr_in addr;
struct hostent * serv;
//
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
#ifndef WINLIB
if(inet_aton(server->mPtr, &(addr.sin_addr)) == 0)
#else
if(InetPton(AF_INET, server->mPtr, &addr) == 1)
#endif
{
// no ip v4 format, search for name
if((serv = gethostbyname(server->mPtr)) == NULL)
{
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
}
addr.sin_addr.s_addr = ((struct in_addr *)(serv->h_addr))->s_addr;
}
#ifndef WINLIB
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
#else
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == EXMOD_SOCKET_ERROR)
#endif
{
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR; /* erreur (TODO plusieurs essais avant erreur ?) */
}
if(AddSocket(e, ctx, sock))
return EXMOD_SOCKET_OK;
else
return EXMOD_SOCKET_ERROR;
}
WAPIDECL int AddSocket(env * e, modContextSocket * ctx, Socket sock)
{
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket->ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
return TRUE; // deja present : RAF
// ajouter
if(! dynCtrl(e, ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return FALSE; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket->ptr;
ctx->poll[ctx->nbSocket].fd = sock;
ctx->poll[ctx->nbSocket++].events = POLLIN; // post incrementation car tableau base 0
return TRUE;
}
WAPIDECL void DelSocket(env * e, modContextSocket * ctx, Socket sock)
{
ctx->poll = (wPoll)ctx->listSocket->ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
if(cpt < --ctx->nbSocket) // autre solution : mettre le fd en negatif : sera ignore par poll
ctx->poll[cpt] = ctx->poll[ctx->nbSocket]; // remplacer par le dernier (bouche le trou tout de suite)
}
WAPIDECL int WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs)
{
ctx->poll = (wPoll)ctx->listSocket->ptr;
#ifdef WINLIB
return WSAPoll(ctx->poll, ctx->nbSocket, timeoutMs);
#else
return poll(ctx->poll, ctx->nbSocket, timeoutMs);
#endif
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
}
WAPIDECL int WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs)
{
ctx->poll = (wPoll)ctx->listSocket->ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
#ifdef WINLIB
return WSAPoll(&ctx->poll[cpt], 1, timeoutMs);
#else
return poll(&ctx->poll[cpt], 1, timeoutMs);
#endif
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
return EXMOD_SOCKET_ERROR;
}
WAPIDECL void FreeSocket(env * e, modContextSocket * ctx, Socket sock)
{
shutdown(sock, 2);
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
DelSocket(e, ctx, sock);
}
WAPIDECL int GetSocketError()
{
#ifdef WINLIB
return WSAGetLastError();
#else
return errno;
#endif
}
// TODO *********************************************************
// https://broux.developpez.com/articles/c/sockets
// https://learn.microsoft.com/fr-fr/windows/win32/winsock/using-winsock
// lecture / ecriture : utiliser send/recv => read/write fait idem avec attribute = 0
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data)
{
int packetLg = 10000; // parametre ?
int timeoutMs = 100; // parametre ?
int nbTot = 0;
// code ici avec une socket non bloquante (sinon a revoir) ; ajouter dans la boucle le poll sur la socket quand besoin de reessayer
for(;;)
{
/* TODO : mettre une limite en nb octets lus ? */
int cr = WaitOneSocketForRead(e, ctx, sock, timeoutMs);
if(cr < 0)
{
if(errno == EINTR)
continue; // reprendre si signal
return -1; /* erreur */
}
if(cr == 0)
return nbTot; /* timeout : renvoi des donnees eventuellement deja lues */
/* */
if( ! dynCtrl(e, data, data->mLg + packetLg, TRUE))
{
return -2; // erreur memoire
}
int nbRead = read(sock, data->mPtr + data->mLg, packetLg);
if(nbRead < 0)
{
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
continue; // reprendre si signal
return -1; /* erreur */
}
if(nbRead == 0)
return -1; /* fin de lecture car fin du client */
/* nbRead positif ici */
data->mLg += nbRead;
nbTot += nbRead;
}
}
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data)
{
//int timeoutMs = 100; // parametre ?
long len = data->mLg, nbTot = 0;
if(len == 0)
return 0;
/* */
for(;;)
{
int nbWrite = write(sock, data->mPtr + nbTot, len);
if(nbWrite == 0)
return -1; /* fin du client */
if(nbWrite < 0)
{
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
{
// TODO : avant continuer, faire un poll sur la socket en ecriture idem read
continue; // reprendre si signal
}
return -1; /* erreur */
}
len -= nbWrite;
nbTot += nbWrite;
if(len <= 0)
return nbTot; /* OK */
}
}
+192 -49
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -25,22 +25,23 @@
#include <time.h>
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#ifdef WINLIB
#include "windows.h"
#else
#include "windows.h" // TODO ici
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
typedef struct {
int error; // dernier code erreur specifique au module
@@ -49,13 +50,15 @@ typedef struct {
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_SYSTEM_FICTMP 1
#define EXMOD_SYSTEM_UNKNOWNVARENV 2
#define EXMOD_SYSTEM_SETENV 3
#define EXMOD_SYSTEM_UNSETENV 4
#define EXMOD_SYSTEM_GETHOST 5
#define EXMOD_SYSTEM_UNAME 6
#define EXMOD_SYSTEM_FORK 7
enum {
EXMOD_SYSTEM_FICTMP = 1,
EXMOD_SYSTEM_UNKNOWNVARENV = 2,
EXMOD_SYSTEM_SETENV = 3,
EXMOD_SYSTEM_UNSETENV = 4,
EXMOD_SYSTEM_GETHOST = 5,
EXMOD_SYSTEM_UNAME = 6,
EXMOD_SYSTEM_FORK = 7
};
static int setError(modEtat * p, int err)
{
@@ -64,13 +67,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
@@ -100,7 +102,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -113,7 +115,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//*** code specifique ici
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
@@ -122,7 +124,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
@@ -132,7 +134,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -146,14 +148,14 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "execute", 7) == 0)
else if(modFnIs(e, "execute", 7))
{
p_etat->error = 0;
// execute(command, returning, capturing)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(!param1 || param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_NUMBER)
else if(!param2 || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
@@ -166,20 +168,30 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(flagCapturing && exc == OK)
{
dynSetLen(e, param3, 0);
#ifdef WINLIB
if (!GetTempPathA(param3->mLgmax, param3->mPtr))
exc = EXMOD_SYSTEM_FICTMP;
else if(!GetTempFileNameA(param3->mPtr, "tmp", 0, e->int_dynamic.mPtr))
exc = EXMOD_SYSTEM_FICTMP;
#else
int fd; // pour avoir un nom de fichier temporaire
dynLet(e, &e->int_dynamic, "/tmp/cap_XXXXXX", 15);
if((fd = mkstemp(e->int_dynamic.mPtr)) == -1)
exc = EXMOD_SYSTEM_FICTMP;
else
close(fd);
#endif
}
if(exc == OK)
{
if(flagCapturing)
{
dynIns(e, &e->int_dynamic, 1, DYN_NONE, param3, '>', DYN_NONE);
cr = system(param1->mPtr);
dynSetAs(e, param3, param1);
dynIns(e, param3, 1 + dynDcount(e, param3, '>', DYN_NONE, DYN_NONE), DYN_NONE, &e->int_dynamic, '>', DYN_NONE);
cr = system(param3->mPtr);
dynRead(e, param3, e->int_dynamic.mPtr);
// purge fichier temp
remove(e->int_dynamic.mPtr); // pbm windows ?!
}
else
{
@@ -190,7 +202,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getEnv", 6) == 0)
else if(modFnIs(e, "getEnv", 6))
{
p_etat->error = 0;
/* utilisation de dynRead qui fait le travail */
@@ -215,7 +227,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "createEnv", 9) == 0)
else if(modFnIs(e, "createEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
@@ -226,16 +238,31 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
// verifier si existe avec getenv, si oui erreur
char * varenv = getenv(param1->mPtr);
if(varenv)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
else if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
#else
int cr = setenv(param1->mPtr, param2->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "updateEnv", 9) == 0)
else if(modFnIs(e, "updateEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
@@ -246,16 +273,24 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
#else
int cr = setenv(param1->mPtr, param2->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "deleteEnv", 9) == 0)
else if(modFnIs(e, "deleteEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
@@ -264,16 +299,24 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, NULL))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
#else
int cr = unsetenv(param1->mPtr); // suppression
if(cr != 0)
{
exc = EXMOD_SYSTEM_UNSETENV;
setError(p_etat, cr);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getOS", 5) == 0)
else if(modFnIs(e, "getOS", 5))
{
p_etat->error = 0;
// uname() donne les infos
@@ -281,6 +324,9 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
dynLet(e, param1, "Windows", DYN_LGNONE);
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
@@ -295,11 +341,13 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EXMOD_SYSTEM_UNAME;
setError(p_etat, errno);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getHostname", 5) == 0)
else if(modFnIs(e, "getHostname", 11))
{
// TODO dans sockMod !!
p_etat->error = 0;
// uname() donne les infos
if(param1->type != VAR_DYNAMIC)
@@ -308,6 +356,48 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
DWORD size = param1->mLgmax;
if (!GetComputerNameA(param1->mPtr, &size))
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
if (gethostname(param2->mPtr, param2->mLgmax) == SOCKET_ERROR)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
struct hostent * host_entry;
host_entry = gethostbyname(param2->mPtr);
if (host_entry == NULL)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
dynLet(e, param2, inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]), DYN_LGNONE);
WSACleanup();
}
}
}
}
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
@@ -335,11 +425,13 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
setError(p_etat, errno);
exc = EXMOD_SYSTEM_UNAME;
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "fork", 4) == 0)
else if(modFnIs(e, "fork", 4))
{
// TODO a supprimer, cf. processMod
p_etat->error = 0;
#ifndef UNIX
// faire differemment sous windows : pas de fork dispo ? CreateProcess()
@@ -360,8 +452,9 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "wait", 4) == 0)
else if(modFnIs(e, "wait", 4))
{
// TODO a supprimer, cf. processMod
#ifndef UNIX
// faire differemment sous windows : pas de wait dispo ? WaitForSingleObject()
#else
@@ -371,19 +464,69 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "kill", 4) == 0)
else if(modFnIs(e, "sendSignal", 10))
{
#ifndef UNIX
// faire differemment sous windows : pas de kill dispo ?
#else
kill(0, SIGTERM); // envoi un signal de fin a tous les fils
#endif
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else
{
number pid, numSignal;
if( var_conv_num(e,param1, &pid) && var_conv_num(e, param2, &numSignal) )
{
pid /= NUM_FACTEUR;
numSignal /= NUM_FACTEUR;
#ifdef WINLIB
// faire differemment sous windows : pas de kill dispo, passer par des evenements (GenerateConsoleCtrlEvent ne fonctionne pas si autre session/cmd/BACK...)
#define SIGINT 2
#define SIGUSR1 10
#define SIGTERM 15
// autoriser tous les process a inter agir...
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
//
HANDLE hEvent = NULL;
char eventName[40] = {0};
if(numSignal == SIGTERM || numSignal == SIGINT)
{
sprintf(eventName, "Global\\wterm%lld", pid);
hEvent= CreateEvent(&sa, FALSE, FALSE, eventName);
}
else if(numSignal == SIGUSR1)
{
sprintf(eventName, "Global\\wdebug%lld", pid);
hEvent = CreateEvent(&sa, FALSE, FALSE, eventName);
}
if(hEvent != NULL) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur : l'event existe deja (et hEvent n'est pas NULL)
{
// envoyer le signal
SetEvent(hEvent);
CloseHandle(hEvent);
}
//
#else
if(numSignal == SIGTERM || numSignal == SIGINT || numSignal == SIGUSR1)
kill(pid, numSignal);
#endif
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "sleep", 5) == 0)
else if(modFnIs(e, "sleep", 5))
{
#ifndef UNIX
// faire differemment sous windows : pas de sleep dispo ?
#ifdef WINLIB
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
// duree attente envoyee en secondes
Sleep(param1->num * 1000 / NUM_FACTEUR); // en millisec.
#else
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
+141
View File
@@ -0,0 +1,141 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
//
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(modFnIs(e, "xxx", 3))
{
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
exc = setError(p_etat, EXMOD_xxx);
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
+63
View File
@@ -0,0 +1,63 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* programme de test unitaire de lib/fonctions */
/* gcc w_src/test.c -s -o exec/test -Wall -m64 -DUNIX -L./exec -l:libw.so -l:encod_lib.so */
#include "encod.h"
env e;
int main(int argc, char * argv[])
{
init_env(&e);
//
Dynamic v, w;
dynInit(&e, &v, DYN_LGMIN);
dynInit(&e, &w, DYN_LGMIN);
//
dynLet(&e, &v, "test des encodages12", DYN_LGNONE);
printf("test base64: %s\n", v.mPtr);
//str2hex(&e, &v, &w);
str2base64(&e, &v, &w);
printf("%s\n", w.mPtr);
dynLet(&e, &v, "dGVzdCBkZXMgZW5jb2RhZ2VzMTI=", DYN_LGNONE);
base642str(&e, &v, &w);
printf("decodage: %s\n", w.mPtr);
dynLet(&e, &v, "303132333435363738394142434445", DYN_LGNONE);
hex2str(&e, &v, &w);
printf("hexa2str: %s\n", w.mPtr);
//
dynFree(&e, &v);
dynFree(&e, &w);
//
return 0;
}
+30 -26
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -20,6 +20,9 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifdef WINLIB
#include "windows.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
@@ -48,11 +51,13 @@ typedef struct {
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_GETCLOCK 1
#define EXMOD_PARAMNUM 2
#define EXMOD_FORMAT_KO 3
#define EXMOD_JETLAG_KO 4
#define EXMOD_DURATION_GETCLOCK 5
enum {
EXMOD_GETCLOCK = 1,
EXMOD_PARAMNUM = 2,
EXMOD_FORMAT_KO = 3,
EXMOD_JETLAG_KO = 4,
EXMOD_DURATION_GETCLOCK = 5
};
static int setError(modEtat * p, int err)
{
@@ -297,13 +302,12 @@ static void FormatTm(env * e, modEtat * p_etat, const char * format, time_t dhm,
}
/* fonctions locales au module FIN */
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -326,7 +330,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -343,7 +347,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
dynInit(e, &p_etat->valNum, DYN_LGMIN);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
@@ -352,7 +356,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
dynFree(e, &p_etat->horodate);
dynFree(e, &p_etat->valNum);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1 == NULL)
@@ -364,7 +368,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -380,7 +384,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "startChrono", 11) == 0)
else if(modFnIs(e, "startChrono", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -398,7 +402,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "lapChrono", 9) == 0)
else if(modFnIs(e, "lapChrono", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -417,7 +421,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setUTC", 6) == 0)
else if(modFnIs(e, "setUTC", 6))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -445,7 +449,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setLocal", 8) == 0)
else if(modFnIs(e, "setLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -480,7 +484,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setNowLocal", 11) == 0)
else if(modFnIs(e, "setNowLocal", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -508,7 +512,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setNowUTC", 9) == 0)
else if(modFnIs(e, "setNowUTC", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -530,7 +534,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "set", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -563,7 +567,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getUTC", 6) == 0)
else if(modFnIs(e, "getUTC", 6))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -583,7 +587,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getLocal", 8) == 0)
else if(modFnIs(e, "getLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -609,7 +613,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -632,7 +636,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "alarmUTCHM", 16) == 0)
else if(modFnIs(e, "alarmUTCHM", 10))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -670,7 +674,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "alarmLocalHM", 18) == 0)
else if(modFnIs(e, "alarmLocalHM", 12))
{
if(p_etat == NULL)
exc = EX_MODETAT;
+122 -14
View File
@@ -29,7 +29,16 @@
#include "var.h"
#include "hashtable.h"
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
{
/* ne pas regarder le type precedent : ecraser ! */
if(v == NULL)
@@ -55,15 +64,19 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
v->lg = 0;
v->lgmax = sep_lgm;
v->ptr[0] = 0;
v->codePage = WCP_DEFAULT;
}
break;
case VAR_BUFFER:
if(sep_lgm < BUF_LGBLOC)
sep_lgm = BUF_LGBLOC;
if(sep_lgm < BUF_LGMINBLOC)
sep_lgm = BUF_LGMINBLOC;
else if((sep_lgm % 32) != 0)
sep_lgm = ((sep_lgm / 32) + 1) * 32; // taille multiple de 32, sinon pile d'elements de 8 et 16 ko !!
if((v->ptr = memalloc(e, sep_lgm)) == NULL)
v->type = VAR_NULL; /* exception levee dans memalloc */
else
{
memset(v->ptr, 0, sep_lgm);
v->lgmax = sep_lgm;
v->read = 0;
v->write = 0;
@@ -98,16 +111,113 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
}
}
void var_ctrl_param(env * e, var * v)
WAPIDECL int varptrtbl_ctrl(env * e, var * v)
{
/* controle que la var "v", si de type PARAM, pointe sur une var toujours existante... */
if(v->type != VAR_PARAM)
return;
/* TODO lire e->par_ptr de type dynamic ??? */
/* dans le cas : hash, puis var de hash, puis clear hash : quid de la var de hash : ras car c'est une copie ! */
/* indique si la var "v" appartient a une var de type pointeur (TRUE) */
if(v == NULL)
return FALSE;
if(v->type == VAR_PARAM)
return FALSE;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad var param, v[3] = ptr de la var param, v[4] = ad var param2, etc.
*/
pointeur * beg = (pointeur *)e->varptrtbl.ptr;
ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
pointeur * curr = beg + 2;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v->ptr)
return TRUE; // deja existant
else
curr += 2;
// pas trouve
return FALSE;
}
void var_free(env * e, var * v, int suivre_par)
WAPIDECL void varptrtbl_maj(env * e, var * v)
{
// ajoute a e->varptrtbl la var si de type "pointeur" : VAR_PARAM, objet...
if(v == NULL)
return;
if(v->type != VAR_PARAM)
return;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad var param, v[3] = ptr de la var param, v[4] = ad var param2, etc.
*/
pointeur * beg = (pointeur *)e->varptrtbl.ptr;
ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
pointeur * curr = ++beg;
ent64 addnb = nb + 1;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v)
{
curr++;
*curr = (pointeur)v->ptr;
return; // deja existant : maj ptr vraie var
}
else
curr += 2;
// pas trouve : ajout a la fin
if(dynCtrl(e, &e->varptrtbl, sizeof(pointeur) * addnb * 2 + 1, TRUE))
{
beg = (pointeur *)e->varptrtbl.ptr; // au cas ou realloc memoire
*((ent64 *)beg) = addnb;
curr = beg + addnb * 2;
*curr-- = (pointeur)v->ptr;
*curr = (pointeur)v;
}
}
WAPIDECL void varptrtbl_del(env * e, var * v)
{
// supprime de e->varptrtbl la var param v
if(v == NULL)
return;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad ptr, v[3] = ptr sur la var param, v[4] = ad ptr 2, etc.
*/
pointeur * beg = (pointeur *)e->varptrtbl.ptr;
ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
pointeur * curr = ++beg;
ent64 savnb = nb;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v)
{
// trouve : mettre le dernier a la place de celui en cours, sauf si c'est le dernier
*((ent64 *)beg) = savnb - 1;
if(nb > 0) // pas de swap a faire si c'est le dernier qui est supprime
{
beg += savnb * 2 - 1; // le dernier
*curr++ = *beg++;
*curr = *beg;
}
}
else
curr += 2;
// pas trouve : RAS
}
WAPIDECL int var_conv_num(env * e, var * v, number * num)
{
if(!v || !num)
return FALSE;
if(v->type == VAR_PARAM)
v = (var *)v->ptr;
if(v->type == VAR_NUMBER)
{
*num = v->num;
return TRUE;
}
if(v->type != VAR_DYNAMIC)
return FALSE;
/* convertir si string, en number */
*num = dynToNumber(e, v);
return(v->mInternal == DYN_OK);
}
WAPIDECL void var_free(env * e, var * v, int suivre_par)
{
var * pvar;
/* */
@@ -145,7 +255,7 @@ void var_free(env * e, var * v, int suivre_par)
v->type = VAR_NULL;
}
void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
{
var * pvar;
/* tient compte de la valeur precedente de la var ; suivre_let/suivre_v = TRUE pour travailler avec la var pointee */
@@ -169,7 +279,6 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
case VAR_DYNAMIC:
var_init(e, let, v->type, 0, v->lg + 1, NULL); // +1 pour le \0 de fin
memcopie(let->ptr, v->ptr, v->lg + 1); // permet de copier le \0 de fin
//memcpy(let->ptr, v->ptr, v->lg + 1);
let->lg = v->lg;
break;
//
@@ -179,8 +288,7 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
// boucler et copier les elements, attention aux cycles !
hashtable_select(e, v);
while(hashtable_next(e, v, e->nom, &pvar))
// TODO copie recursive + copie de la var "pvar"
hashtable_do(e, HASH_WRITE, let, e->nom, &pvar);
hashtable_do(e, HASH_WRITE, let, e->nom, &pvar); // WRITE appelle var_let : recursif de fait
break;
//
case VAR_PARAM:
+10 -4
View File
@@ -23,10 +23,16 @@
#ifndef VAR_H
#define VAR_H
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
void var_ctrl_param(env * e, var * v);
void var_free(env * e, var * v, int suivre_par);
void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
#include "apidecl.h"
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
WAPIDECL int var_conv_num(env * e, var * v, number * num);
WAPIDECL void var_free(env * e, var * v, int suivre_par);
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
WAPIDECL int varptrtbl_ctrl(env * e, var * v);
WAPIDECL void varptrtbl_maj(env * e, var * v);
WAPIDECL void varptrtbl_del(env * e, var * v);
/* ********************************************** */
#endif
+18
View File
@@ -0,0 +1,18 @@
set WBIN=exec
set WLIB=.
set WSRC=.
exec\lwc prg.w
exec\lwa prg.wa
exec\lw prg
rem
exec\lwc comp.w
exec\lwa comp.wa
exec\lw comp
rem
exec\lwc pdf.w
exec\lwa pdf.wa
exec\lw pdf
rem
exec\lwc debug.w
exec\lwa debug.wa
exec\lw debug 1234
+128
View File
@@ -0,0 +1,128 @@
; regles lex des token w
; \r est supprime des lignes et \n sert de separateur de lignes : non present
blank: (1,*,#20#09)
comment: (1,1,#3B) (0,*,#00-#FF)
begin: begin
background: background
library: library
end: end
except: except
throw: throw
catch: catch
include: include
sub: sub
endsub: endsub
if: if
then: then
else: else
elseif: elseif
endif: endif
do: do
call: call
invoke: invoke
return: return
returnon: returnon
loop: loop
endloop: endloop
foreach: foreach
in: in
like: like
endfor: endfor
break: break
breakon: breakon
continue: continue
continueon: continueon
nop: nop
part: part
echonl: echonl
echo: echo
input: input
declare: declare
let: let
delet: delet ; unlet ??
new: new
class: class
this: this
parent: parent
hold: hold
precision: precision
setsep: setsep
int: int
frac: frac
abs: abs
neg: neg
round: round
type: type
len: len
count: count
dcount: dcount
field: field
index: index
search: search
change: change
format: format
insert: insert
remove: remove ; delete (dynamic)
tonum: tonum
tostring: tostring
equal: =
diff: (1,1,#23) ; #
gt: >
lt: <
gte: >=
lte: <=
and: and
or: or
not: not
beginpar: (1,1,#28) ; (
endpar: (1,1,#29) ; )
beginh: (1,1,#7B) ; {
endh: (1,1,#7D) ; }
begins: (1,1,#5B) ; [
ends: (1,1,#5D) ; ]
indirect: !
typeof: ? ; typeof ??
stringdq: (1,1,#22) (0,765,#20-#21#23-#EF) (1,1,#22) ; contenu chaine : car car car #FF (en majuscule), a verifier lors du parse (hexa -> binaire + controle)
stringq: (1,1,#27) (0,765,#20-#26#28-#EF) (1,1,#27) ; idem
ident: (1,1,a-zA-Z) (0,23,a-zA-Z0-9)
varsys: @ (1,*,a-z)
numberdec: (1,13,0-9) . (0,5,0-9)
numberint: (1,13,0-9)
minus: (1,1,#2D) ; -
plus: (1,1,#2B) ; +
multiply: (1,1,#2A) ; *
divide: (1,1,#2F) ; /
divident: (1,1,#5C) ; \
modulo: (1,1,#25) ; %
concat: (1,1,#3A) ; :
listesep: (1,1,#2C) ; ,
identsep: (1,1,#2E) ; .
modsep: &
other: (1,1,#00-#FF)
; fin des regles w.lex
+115
View File
@@ -0,0 +1,115 @@
<?php
/*************************************************************************************
* w.php
* -----
* Author: FDE
* Contributors:
* Copyright: (c) 2023
* Release Version: 1.0
* Date Started: 05/10/2024
*
* W language file for GeSHi.
*
* a mettre ici : /lamp0/web/vhosts/www.lanisys.fr/htdocs/wiki/vendor/geshi/geshi/src/geshi
*
*************************************************************************************
*
* This file is part of GeSHi.
*
* GeSHi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GeSHi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GeSHi; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
************************************************************************************/
$language_data = array (
'LANG_NAME' => 'W',
'COMMENT_SINGLE' => array(1 => ';'),
'COMMENT_MULTI' => array(),
'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,
'QUOTEMARKS' => array('"', '\''),
'ESCAPE_CHAR' => '',
'KEYWORDS' => array(
1 => array(
'begin', 'background', 'library', 'except', 'end', 'sub',
'endsub', 'include', 'loop', 'endloop', 'return', 'returnon',
'break', 'breakon', 'continue', 'continueon', 'throw', 'catch',
'foreach', 'in', 'like', 'if', 'then', 'elseif', 'else',
'endif', 'endfor','echo', 'echonl', 'input', 'nop', 'part', 'declare',
'let', 'do', 'call', 'invoke', 'delet', 'class', 'free',
'new', 'this', 'parent', 'precision', 'setsep'
),
2 => array(
'or', 'and', 'not', 'int', 'frac', 'abs', 'neg', 'type', 'typeof',
'tonum', 'tostring', 'count', 'len', 'format', 'dcount',
'round', 'field', 'index', 'search', 'change', 'insert', 'remove'
)
),
'SYMBOLS' => array(
'(', ')', '{', '}', '[', ']'
),
'CASE_SENSITIVE' => array(
GESHI_COMMENTS => false,
1 => true,
2 => true,
),
'STYLES' => array(
'KEYWORDS' => array(
1 => 'color: #b1b100; font-weight: bold;',
2 => 'color: #b1b100;'
),
'COMMENTS' => array(
1 => 'color: #666666; font-style: italic;',
),
'ESCAPE_CHAR' => array(
0 => 'color: #000099; font-weight: bold;'
),
'BRACKETS' => array(
0 => 'color: #000066;'
),
'STRINGS' => array(
0 => 'color: #009900;'
),
'NUMBERS' => array(
0 => 'color: #CC0000;'
),
'METHODS' => array(
1 => 'color: #006600;'
),
'SYMBOLS' => array(
0 => 'color: #000066;'
),
'REGEXPS' => array(
),
'SCRIPT' => array(
0 => '',
1 => '',
)
),
'URLS' => array(
1 => '',
2 => ''
),
'OOLANG' => false,
'OBJECT_SPLITTERS' => array(
1 => '\\'
),
'REGEXPS' => array(
),
'STRICT_MODE_APPLIES' => GESHI_NEVER,
'SCRIPT_DELIMITERS' => array(),
'HIGHLIGHT_STRICT_BLOCK' => array(
0 => false,
1 => false
)
);
+100
View File
@@ -0,0 +1,100 @@
blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60,format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70,lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80,indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90,multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99
1,-1,20:09
1,1,3B;0,-1,00-FF
1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E
1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64
1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79
1,1,65;1,1,6E;1,1,64
1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74
1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77
1,1,63;1,1,61;1,1,74;1,1,63;1,1,68
1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65
1,1,73;1,1,75;1,1,62
1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62
1,1,69;1,1,66
1,1,74;1,1,68;1,1,65;1,1,6E
1,1,65;1,1,6C;1,1,73;1,1,65
1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66
1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66
1,1,64;1,1,6F
1,1,63;1,1,61;1,1,6C;1,1,6C
1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65
1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E
1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E
1,1,6C;1,1,6F;1,1,6F;1,1,70
1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70
1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68
1,1,69;1,1,6E
1,1,6C;1,1,69;1,1,6B;1,1,65
1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72
1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B
1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E
1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65
1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E
1,1,6E;1,1,6F;1,1,70
1,1,70;1,1,61;1,1,72;1,1,74
1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C
1,1,65;1,1,63;1,1,68;1,1,6F
1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74
1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65
1,1,6C;1,1,65;1,1,74
1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74
1,1,6E;1,1,65;1,1,77
1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73
1,1,74;1,1,68;1,1,69;1,1,73
1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74
1,1,68;1,1,6F;1,1,6C;1,1,64
1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E
1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70
1,1,69;1,1,6E;1,1,74
1,1,66;1,1,72;1,1,61;1,1,63
1,1,61;1,1,62;1,1,73
1,1,6E;1,1,65;1,1,67
1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64
1,1,74;1,1,79;1,1,70;1,1,65
1,1,6C;1,1,65;1,1,6E
1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74
1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74
1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64
1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78
1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68
1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65
1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74
1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74
1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65
1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D
1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67
1,1,3D
1,1,23
1,1,3E
1,1,3C
1,1,3E;1,1,3D
1,1,3C;1,1,3D
1,1,61;1,1,6E;1,1,64
1,1,6F;1,1,72
1,1,6E;1,1,6F;1,1,74
1,1,28
1,1,29
1,1,7B
1,1,7D
1,1,5B
1,1,5D
1,1,21
1,1,3F
1,1,22;0,765,20-21:23-EF;1,1,22
1,1,27;0,765,20-26:28-EF;1,1,27
1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39
1,1,40;1,-1,61-7A
1,13,30-39;1,1,2E;0,5,30-39
1,13,30-39
1,1,2D
1,1,2B
1,1,2A
1,1,2F
1,1,5C
1,1,25
1,1,3A
1,1,2C
1,1,2E
1,1,26
1,1,00-FF