Author SHA1 Message Date
fred 0d32522c75 WIP 2026-10-31 20:37:56 +01:00
fred d65cf3d2fa fix 2026-10-11 20:04:54 +02:00
fred e6dbc8c814 feat: securesock mod and http protocole mod 2026-10-11 11:39:00 +02:00
fred dc3e7c882d feat: secure socket Mod 2026-10-04 19:09:48 +02:00
fred 550c4ff5d6 feat: timeMod with alarm management 2026-09-27 13:02:28 +02:00
fred b100fd2959 WIP timeMod with alarms 2026-09-26 21:15:55 +02:00
fred 598d7321c4 fix: numstr stack cleared when exception throwed and before each W instruction (SRCL) 2026-09-20 19:25:05 +02:00
fred 3d0629b628 feat: calculs 64 bits justes avec détection dépassement de capacité 2026-09-20 17:21:12 +02:00
fred bce2033fc1 feat: timeMod ok for timedate management 2026-09-13 19:09:21 +02:00
fred 6c58dc64cc Merge branch 'dev/alpha-9' of https://git.lanisys.fr/lanisys/W into dev/alpha-9 2026-09-12 13:16:58 +02:00
fred 6894685bb9 WIP timeMod, adler32 hashing, optimized hashtable, process management 2026-09-12 13:16:42 +02:00
nicolas 7f5fb882da Ajout section installation
Ajout de la section installation. Lors des prochaines branches, la bonne version du readme sera présente. Sinon, celle du master aurait été remplacé

Signed-off-by: Deville <nicolas@lanisys.fr>
2026-08-09 20:17:28 +02:00
fred 97065a4e47 fix: lex bug (hard-coded token number) + xml.w 2026-08-09 19:00:43 +02:00
fred 4ed586d2dc feat: named parameters invoking C modules
feat: lex with state management
2026-08-07 17:30:57 +02:00
fred a20c4733ad WIP named parameters invoking C modules + code cleaning 2026-08-02 18:26:50 +02:00
fred ecb07de56e WIP named parameters 2026-08-01 21:02:46 +02:00
fred 9b04cf31ac Merge branch 'dev/alpha-9' of https://git.lanisys.fr/lanisys/W into dev/alpha-9
# Conflicts:
#	pdf_lib.c
2026-08-01 18:49:19 +02:00
fred 6f88a95edd feat: named parametres
feat: cipher AES 128/192/256 bits
feat: pfdMod enables dynamic number of pages + barcode ean128
WIP: named parameters when invoking C module
2026-08-01 18:42:38 +02:00
Lanisys 48719bc369 feat: pdfMod with unknown page number & CAB EAN128 2026-07-26 17:29:44 +02:00
Lanisys 4e7ba72eda fix: readme 2026-07-19 16:14:03 +02:00
Lanisys 726df4dcb9 fix: review readme 2026-07-19 16:12:19 +02:00
fred b6bea78591 feat: release alpha-8 2026-07-14 10:19:52 +02:00
fred 0445f10ebe WIP VAR_PARAM management 2026-06-28 18:01:09 +02:00
fred ad317a2070 feat: ssh_lib, VAR_PARAM management (when hashtable element) 2026-06-28 16:12:04 +02:00
fred e0eaf6f9e8 WIP exception bubbling 2026-06-14 18:14:25 +02:00
fred b70cee802b WIP exception bubbling
WIP ssh lib
2026-06-14 15:45:35 +02:00
fred 84bdea04ea WIP setup for secure socket (openSSL)
fix: cipher lib
2026-06-07 18:26:38 +02:00
fred 747c9819f1 feat: cipher aes128 finalized, aes192 & aes256 to test 2026-05-30 18:58:54 +02:00
fred 44b447e9af feat: hash mod, websocket mod, cipher mod 2026-05-30 17:15:23 +02:00
fred 760020f30e WIP socket, sqlite, createprocess 2026-04-25 19:39:08 +02:00
fred 3f4f548e55 WIP socket module 2026-04-25 15:30:48 +02:00
fred 4c80dff382 WIP linux/windows socket 2026-04-12 18:00:39 +02:00
fred 632df00f8d WIP pdf, socket 2026-04-11 18:17:31 +02:00
fred 667531bee8 WIP 2026-04-08 21:31:51 +02:00
fred 0ec33cbe5a WIP sockMod 2026-04-04 20:29:01 +02:00
fred efbd77e7fb WIP http, sock, template 2026-04-04 18:54:42 +02:00
fred 89dcd0b594 WIP http fcgi 2026-04-04 15:40:08 +02:00
fred 3b68b7d408 WIP http fastcgi 2026-03-31 20:56:49 +02:00
fred e39c18d606 WIP VAR_PARAM management
deat: fcgi_lib
2026-03-29 19:57:17 +02:00
fred fc29d78e57 feat: add rename/remove/append to fileMod + error code 2026-03-28 21:25:58 +01:00
fred cb12b9d54f WIP var_param management 2026-03-28 20:59:27 +01:00
fred bcd62e6913 WIP dynamic convert 2026-03-27 13:52:04 +01:00
fred 89a3c4d5c2 fix: except when returning from LIBR / SUB 2026-03-21 20:55:32 +01:00
fred 103ad22814 feat: add sqrt and exp functions 2026-03-21 19:17:26 +01:00
fred c69d94e6c8 feat: compressed wp programs (assembler and runtime) 2026-03-21 14:50:57 +01:00
fred f994cc8188 fix: DEXV/DEXH/DEXI from number to dynamic
feat: lexMod getToken function
test program calc.w
2026-03-20 20:47:48 +01:00
fred e87d3f9237 feat: convMod (renaming encod_lib), add @variables
fix: lexMod, abs() usage in runtime
feat: dynamic new function (not used yet)
WIP sqrt and exp function in runtime, to do instruction compilation
feat: first real w prog (calculator RPN)
2026-03-20 17:39:44 +01:00
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
85 changed files with 297848 additions and 5065 deletions

No files matched your search

+67 -40
View File
@@ -6,7 +6,7 @@ W
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -24,32 +24,7 @@ W
along with this program. If not, see <https://www.gnu.org/licenses/>.
```
# Execution
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
```
# Infos
voir les modules en memoire :
```
ldd
objdump/readelf (moins bien)
cat /proc/*/maps et faire des grep pour voir les .so et module chargés par opendl
```
# 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 && rm $1.wa && exec/lw $1
```
# Site Web
https://w.lanisys.fr/
# French
## LANGAGE W
@@ -59,19 +34,10 @@ 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
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.
L'utilitaire *lwf* permettent de formatter le code source.
Pour démarrer, premier programme d’exemple :
``` w
@@ -82,4 +48,65 @@ except
end
```
Voici la description complète du [langage W](/w/instr).
# Installation
Installation depuis les dépôts officiels pour base Debian/Ubuntu:
```
sudo apt update
sudo apt install ca-certificates curl
sudo curl -fsSL http://apt.lanisys.fr/public.key -o /etc/apt/keyrings/wlanguage.gpg
sudo tee /etc/apt/sources.list.d/wlanguage.sources <<EOF
Types: deb
URIs: http://apt.lanisys.fr
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: main
Signed-By: /etc/apt/keyrings/wlanguage.gpg
EOF
sudo apt update
sudo apt install wlanguage
sudo exec bash -l
```
Voici la description complète du [langage W](https://w.lanisys.fr/doku.php?id=reference).
# English
## W LANGUAGE
### Overview
The goal of the W language is to be simple, efficient, and robust.
It comes with a compiler that generates *p-code* binary code,
compatible with any platform.
A W p-code executor will be available for Linux and other operating systems.
W programs will be callable from other programs, much like a plugin system.
The *lwf* utility is available for formatting source code.
To get started, here is a first example program:
``` w
; The famous Hello World in W
begin hello
echonl "Hello world !"
except
end
```
# Installation
Installation from the official repositories for Debian/Ubuntu-based systems:
```
sudo apt update
sudo apt install ca-certificates curl
sudo curl -fsSL http://apt.lanisys.fr/public.key -o /etc/apt/keyrings/wlanguage.gpg
sudo tee /etc/apt/sources.list.d/wlanguage.sources <<EOF
Types: deb
URIs: http://apt.lanisys.fr
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: main
Signed-By: /etc/apt/keyrings/wlanguage.gpg
EOF
sudo apt update
sudo apt install wlanguage
sudo exec bash -l
```
Here is the complete description of the [W language](https://w.lanisys.fr/doku.php?id=reference).
+15 -5
View File
@@ -1,7 +1,9 @@
#define ARG_DEBUG "d"
#define ARG_TRACE "t"
#define ARG_DISASM "d"
#define ARG_DEBUG "d" /* avec lw */
#define ARG_TRACE "t" /* avec lw */
#define ARG_DISASM "u" /* avec lwa */
#define ARG_COMPRESS "c" /* avec lwa */
#define ARG_SOURCE "s" /* avec lwc */
void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
{
@@ -16,6 +18,13 @@ void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
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(strcmp(argv[a], "-" ARG_DISASM) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_DISASM, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_COMPRESS) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_COMPRESS, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_SOURCE) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_SOURCE, 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)
@@ -27,6 +36,7 @@ void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
else
{
// premier argument ne commencant pas par "-" : nom du prog wp
dynDel(e, arg, 6, clc, cFM, cVM, 1);
for( ; a < argc; a++)
dynStoreSz(e, arg, 2, ++cpt, argv[a], DYN_LGNONE, cFM, cVM);
break;
@@ -45,8 +55,8 @@ void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
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<1> = options de lw en MV
arg<2> = prog w et ses 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
+61 -109
View File
@@ -32,6 +32,7 @@
#include "dynamic.h"
#include "instr.h"
#include "arg.c"
#include "lzw.h"
env e;
@@ -47,12 +48,16 @@ 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
*/
/* contexte pour lzw */
modContextLzw ctxCompress;
/* -------------------- */
ent64 lap = 0; /* calcul temps du programme (hors init, alloc et free), en ms */
@@ -82,8 +87,10 @@ 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;
@@ -99,7 +106,7 @@ void PCODEP(int x)
pcode.ptr[posOffset++]=((octet)x);
}
int assembler(env * e, char * fichier, int * cptLig)
int assembler(env * e, char * fichier, int * cptLig, int compress)
{
//#define PCODE(x) {dynConcatSz(e,&pcode,"0",1);pcode.ptr[pcode.mLg-1]=((octet)x);}
//#define PCODEP(x) pcode.ptr[pcode.mLg++]=((octet)x);
@@ -244,7 +251,7 @@ int assembler(env * e, char * fichier, int * cptLig)
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
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
@@ -292,7 +299,7 @@ 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);
@@ -407,10 +414,12 @@ int assembler(env * e, char * fichier, int * cptLig)
case IN_SELE:
case IN_RNXT:
case IN_CPHA:
case IN_CPHH:
// PVAT / TYPO / PSHT / SELE / RNXT / CPHA
PCODE(instr);
break;
case IN_CPSH:
case IN_CPAN:
case IN_CPHN:
case IN_PARM:
case IN_PVAR:
case IN_PVAH:
@@ -428,7 +437,7 @@ int assembler(env * e, char * fichier, int * cptLig)
case IN_NLET:
case IN_PVHD:
case IN_PVID:
// CPSH / PARM / PVAR / PVAH / PVAI / DELE / NLET / PHDE / PIDE
// CPAN / CPHN / PARM / PVAR / PVAH / PVAI / DELE / NLET / PHDE / PIDE
//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
@@ -468,87 +477,50 @@ int assembler(env * e, char * fichier, int * cptLig)
ret = -9; // code comparaison inconnu
break;
case IN_ADDN:
// ADDN
case IN_SBCN:
// SBCN
case IN_MULN:
// MULN
case IN_DIVN:
// DIVN
case IN_DIVE:
// DIVE
case IN_MODN:
// MODN
case IN_INTE:
// INTE
case IN_FRAC:
// FRAC
case IN_NEGN:
// NEGN
case IN_ABSN:
// ABSN
case IN_SQRT:
case IN_IEXP:
case IN_DTON:
// DTON
case IN_NTOD:
// NTOD
case IN_HLET:
// HLET
case IN_CCAT:
// CCAT
case IN_ROUN:
// ROUN
case IN_TYPE:
// TYPE
case IN_LENG:
// LENG
case IN_COUN:
// COUN
case IN_DCOF:
// DCOF
case IN_DCOS:
// DCOS
case IN_INDX:
// INDX
case IN_FIEL:
// FIEL
case IN_FLDF:
// FLDF
case IN_FLDS:
// FLDS
case IN_SSTR:
// SSTR
case IN_SSEP:
// SSEP
case IN_FMTA:
// FMTA
case IN_FMTT:
// FMTT
case IN_FMTS:
// FMTS
case IN_SRCH:
// SRCH
case IN_SCHS:
// SCHS
case IN_SSRC:
case IN_SSCS:
case IN_CHNG:
// CHNG
case IN_INSE:
// INSE
case IN_INSS:
// INSS
case IN_REMV:
// REMV
case IN_REMS:
// REMS
case IN_TONU:
// TONU
case IN_TOST:
// TOST
case IN_DEXV:
// DEXV
case IN_DESV:
// DESV
case IN_DEZV:
// DEZV
case IN_SADV:
case IN_VLET:
case IN_HCOU:
@@ -615,7 +587,7 @@ int assembler(env * e, char * fichier, int * cptLig)
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
@@ -699,7 +671,9 @@ int assembler(env * e, char * fichier, int * cptLig)
PCODE(tmp.mPtr[p]);
break;
case IN_INCL:
// INCL (lg=0 possible si rien)
// INCL (lg=0 possible si rien) - ne pas mettre dans le pcode car ne sert plus
i++;
break;
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;
@@ -736,10 +710,6 @@ int assembler(env * e, char * fichier, int * cptLig)
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p]);
break;
case IN_TEST:
// TEST
PCODE(instr);
break;
case IN_ENDL:
case IN_ENDP:
// ENDL / ENDP : fin de librairie / prog directement executable
@@ -774,6 +744,14 @@ int assembler(env * e, char * fichier, int * cptLig)
// 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';
if(compress)
{
/* compression lzw avant */
initLzw(e, &ctxCompress);
if(setLzw(e, &pcode, &ctxCompress, 0) != OK)
printf("Erreur de compression Lzw du binaire wp - ecriture en clair\n");
freeLzw(e, &ctxCompress);
}
dynWrite(e, &pcode, tmp.mPtr);
}
//
@@ -809,6 +787,19 @@ int disassembler(env * e, char * fichier)
dynFree(e, &pcode);
return -1;
}
/* si bit 7 premier octet = 0 => compresse */
if(pcode.ptr[0] < 128)
{
/* decompression lzw avant */
initLzw(e, &ctxCompress);
if(getLzw(e, &pcode, &ctxCompress, 0) != OK)
{
printf("Erreur de decompression Lzw du binaire wp \n");
dynFree(e, &pcode);
return -1;
}
freeLzw(e, &ctxCompress);
}
dynInit(e, &tmp, DYN_LGMIN);
dynInit(e, &varsys, DYN_LGMIN);
dynInit(e, &niv, DYN_LGMIN);
@@ -936,7 +927,8 @@ int disassembler(env * e, char * fichier)
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_CPSH:
case IN_CPAN:
case IN_CPHN:
case IN_PARM:
case IN_PVAR:
case IN_PVAH:
@@ -955,8 +947,8 @@ int disassembler(env * e, char * fichier)
case IN_PVHD:
case IN_PVID:
case IN_PNAM:
case IN_INCL:
// CPSH / PARM / PVAR / PVAH / PVAI / DELE / NLET / PNAM / INCL / PHDE / PIDE
//case IN_INCL:
// CPAN / CPHN / PARM / PVAR / PVAH / PVAI / DELE / NLET / PNAM / INCL / PHDE / PIDE
si++;
lg = pcode.ptr[si++];
for(int p = 0; p < lg; p++)
@@ -993,87 +985,50 @@ int disassembler(env * e, char * fichier)
dumpHex(&pcode, si_instr, si);
break;
case IN_ADDN:
// ADDN
case IN_SBCN:
// SBCN
case IN_MULN:
// MULN
case IN_DIVN:
// DIVN
case IN_DIVE:
// DIVE
case IN_MODN:
// MODN
case IN_INTE:
// INTE
case IN_FRAC:
// FRAC
case IN_NEGN:
// NEGN
case IN_ABSN:
// ABSN
case IN_SQRT:
case IN_IEXP:
case IN_DTON:
// DTON
case IN_NTOD:
// NTOD
case IN_HLET:
// HLET
case IN_CCAT:
// CCAT
case IN_ROUN:
// ROUN
case IN_TYPE:
// TYPE
case IN_LENG:
// LENG
case IN_COUN:
// COUN
case IN_DCOF:
// DCOF
case IN_DCOS:
// DCOS
case IN_INDX:
// INDX
case IN_FIEL:
// FIEL
case IN_FLDF:
// FLDF
case IN_FLDS:
// FLDS
case IN_SSTR:
// SSTR
case IN_SSEP:
// SSEP
case IN_FMTA:
// FMTA
case IN_FMTT:
// FMTT
case IN_FMTS:
// FMTS
case IN_SRCH:
// SRCH
case IN_SCHS:
// SCHS
case IN_SSRC:
case IN_SSCS:
case IN_CHNG:
// CHNG
case IN_INSE:
// INSE
case IN_INSS:
// INSS
case IN_REMV:
// REMV
case IN_REMS:
// REMS
case IN_TONU:
// TONU
case IN_TOST:
// TOST
case IN_DEXV:
// DEXV
case IN_DESV:
// DESV
case IN_DEZV:
// DEZV
case IN_SADV:
case IN_VLET:
case IN_HCOU:
@@ -1136,6 +1091,8 @@ int disassembler(env * e, char * fichier)
// RNXT
case IN_CPHA:
// CPHA
case IN_CPHH:
// CPHJ
case IN_PSHV:
// PSHV
case IN_POPV:
@@ -1240,12 +1197,6 @@ int disassembler(env * e, char * fichier)
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_TEST:
// TEST
si++;
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_ENDS:
// ENDS
si++;
@@ -1283,10 +1234,10 @@ int main(int argc, char * argv[])
/* avis de licence */
printf("W language Copyright 2024,2025 lanisys.fr\n");
printf("This program comes with ABSOLUTELY NO WARRANTY;\nThis is free software, and you are welcome to redistribute it\nunder certain conditions (GPL-3.0-or-later)\n\n");
/* argument : fichier a assembler/desassembler (si -d) */
/* argument : fichier a assembler/desassembler (si -u), assembler avec compression lzw (si -c) */
if(argc < 2)
{
printf("Usage: lwa [-d] [-WLIB:<chemin>] <fichier.wa|fichier.wp>\n");
printf("Usage: lwa [-c|-u] [-WLIB:<chemin>] <fichier.wa|fichier.wp>\n");
exit(-1);
}
/* */
@@ -1329,11 +1280,12 @@ int main(int argc, char * argv[])
}
else
{
int compress = dynLocateSz(&e, &arg, ARG_COMPRESS, cVM, 1, cFM);
int numLig = 0;
#ifndef UNIX
if((cr = assembler(&e, wlib.mPtr, &numLig)) != OK)
if((cr = assembler(&e, wlib.mPtr, &numLig, compress)) != OK)
#else
if((cr = assembler(&e, wlib.mPtr, &numLig)) != OK)
if((cr = assembler(&e, wlib.mPtr, &numLig, compress)) != OK)
#endif
{
printf("Erreur %d a la ligne %d\n", cr, numLig);
+17 -11
View File
@@ -76,9 +76,16 @@ WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
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 = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* uniquement lecture dans VAR_DYNAMIC : raz var sinon */
if(v->type != VAR_DYNAMIC)
{
var_free(e, v, TRUE);
@@ -108,7 +115,6 @@ WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
{
/* 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)
@@ -120,9 +126,7 @@ WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
{
/* 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;
}
}
@@ -136,10 +140,16 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
if(varbuf == NULL || v == NULL)
return;
if(v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* uniquement ecriture d'une VAR_DYNAMIC */
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 */
@@ -161,7 +171,6 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
*(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
@@ -188,7 +197,6 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
{
/* 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
@@ -198,9 +206,7 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
{
/* 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;
}
}
+269
View File
@@ -0,0 +1,269 @@
; w faire une calculatrice RPN : nombre, opérateurs + - * / , fonctions neg frac int mod div , commandes : quitter, clear vide pile (utiliser le module lex), dup (duplique dernier elemn pile), pop enleve dernier element, precision
begin
sub displayStack(stack)
declare size, one, minusOne, elem
let size = dcount(stack)
if size = 0 then
echonl "<empty stack>"
return
endif
let one = 1
let minusOne = neg(one)
foreach elem in size, one, minusOne
echonl format(elem, @right, '0', 2):'> ':format(stack{elem}, @right, ' ', 20)
endfor
except
endsub
;
declare rules, crules, Rule ; lex rules and compiled rules, Rule (pour echapper # 2 fois => #23#32#33)
let crules = ''
let rules = 'integer: int '
let rules{2} = 'fractionnal: frac '
let rules{3} = 'absolute: abs '
let rules{4} = 'negation: neg '
let rules{5} = 'round0: round0 '
let rules{6} = 'round1: round1 '
let rules{7} = 'round2: round2 '
let rules{8} = 'round3: round3 '
let rules{9} = 'round4: round4 '
let rules{10} = 'random: rnd ; random '
let rules{11} = 'varsys: @ (1,*,a-z) '
let rules{12} = 'number: (0,1,#23#32#332D) (1,13,0-9) . (0,5,0-9) ' ; corriger le double 'escape' car - est un car reserve lex (- => #2D => #23#32#33#23#33#32#23#34#34) car sinon compil/assembleur decode mal le -
let rules{13} = 'integernumber: (0,1,#23#32#332D) (1,13,0-9) '
let rules{14} = 'minus: (1,1,#23#32#332D) ; - '
let rules{15} = 'plus: (1,1,#2B) ; + '
let rules{16} = 'multiply: (1,1,#2A) ; * '
let rules{17} = 'divide: (1,1,#2F) ; / '
let rules{18} = 'integerdivide: (1,1,#5C) ; \ '
let rules{19} = 'modulus: (1,1,#25) ; % '
let rules{20} = 'quit: quit '
let rules{21} = 'dup: dup '
let rules{22} = 'pop: pop '
let rules{23} = 'clear: clear '
let rules{24} = 'space: (1,1,#23#32#3320) '
let rules{25} = 'other: (1,1,#23#32#3300-#23#32#33FF)'
let rules = change(rules, @fm, @lf)
part 1
let Rule = {}
invoke lex&compile(rules, crules, Rule)
part 2
; todo mettre la sub qui suit dans le module lex (? pbm il faut 4/5 params)
declare tok
let tok = {}
sub getToken(tokenList, tokenIndex, tokenNumber, value)
let tokenNumber = tokenList{2, tokenIndex}
if tokenNumber # '' then
declare hexa
let hexa = ''
let hexa = tokenList{1, tokenIndex}
invoke conv&fromHexa(hexa, value)
endif
; si besoin
invoke lex&getToken(tokenList, tokenIndex, tok)
except
endsub
;
echonl "wcalc => + - * / \ % int frac abs neg rnd round0 round1 round2 round3 round4 @pi pop dup clear quit"
;
declare value, stack, token, ind, ruleNumber, ruleValue
let value = ''
let token = ''
let stack = ''
loop
do displayStack(stack)
echo 'wcalc: '
let value = ''
input value
invoke lex&analyze(crules, value, token)
; -----------------------------------------------
; token{1/2/3} en MV : chaine hexa, no token, ordinal_position
let ind = 0
let ruleValue = ''
let ruleNumber = 0
loop
let ind = ind + 1
do getToken(token, ind, ruleNumber, ruleValue)
breakon ruleNumber = ''
continueon ruleNumber = Rule.space
;
if ruleNumber = Rule.other then
echonl 'Syntax error'
break;
; -----------------------------------------------
elseif ruleNumber = Rule.dup then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack = insert(stack, stack{1}, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.pop then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.clear then
let stack = ''
; -----------------------------------------------
elseif ruleNumber = Rule.number or ruleNumber = Rule.integernumber then
if dcount(stack) > 15 then
echonl "Stack full error"
else
let stack = insert(stack, ruleValue, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.random then
if dcount(stack) > 15 then
echonl "Stack full error"
else
declare rnd
let rnd = 0
invoke random&get(rnd)
let stack = insert(stack, rnd, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.varsys then
if dcount(stack) > 15 then
echonl "Stack full error"
else
if ruleValue = '@pi' then
let stack = insert(stack, @pi, 1)
else
echonl "Unknown constant"
endif
endif
; -----------------------------------------------
elseif ruleNumber = Rule.plus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} + stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.minus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} - stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.divide then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} / stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.integerdivide then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} \ stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.modulus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} % stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.multiply then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} * stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.negation then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = neg(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.integer then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = int(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.fractionnal then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = frac(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.absolute then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = abs(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round0 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 0)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round1 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round2 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 2)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round3 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 3)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round4 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 4)
endif
endif
; -----------------------------------------------
breakon ruleNumber = Rule.quit
endloop
breakon ruleNumber = Rule.quit
endloop
echonl "Bye :)"
except
echonl "Exception line ":@exceptline
if @part = 1 then
declare err
let err = 0
invoke lex&error(err)
echonl "lex error : ":err
endif
end
+48
View File
@@ -0,0 +1,48 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "langage.h"
#include "dynamic.h"
typedef struct {
Dynamic key; /* keeps the keys during cipher/decipher */
} modContextCipher;
/* codes a passer a la fonction setError */
enum {
CIPHER_OK = 0,
CIPHER_KEYLENGTH = 1,
CIPHER_MEM = 2
};
WAPIDECL void cipherInit(env * e, modContextCipher * ctx);
WAPIDECL void cipherEnd(env * e, modContextCipher * ctx);
WAPIDECL long cipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long cipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long cipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
+273
View File
@@ -0,0 +1,273 @@
/* **********************************************
__ __ __
\ \/ \/ / 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"
/* ============================================================================================= */
#include "cipher.h"
typedef struct {
int error; // dernier code erreur specifique au module
modContextCipher ctxMod;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
#include "mod.c"
#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 */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
cipherInit(e, &p_etat->ctxMod);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
cipherEnd(e, &p_etat->ctxMod);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toAES128", 8))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramEncrypted = getParam(e, "encrypted", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramEncrypted->type != VAR_DYNAMIC)
var_let(e, paramEncrypted, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, cipher_AES128(e, &p_etat->ctxMod, paramKey, paramPlaintext, paramEncrypted));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromAES128", 10))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramEncrypted = getParam(e, "encrypted", 9);
var * paramPlaintext = getParam(e, "plaintext", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramEncrypted->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, decipher_AES128(e, &p_etat->ctxMod, paramKey, paramEncrypted, paramPlaintext));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "toAES192", 8))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramEncrypted = getParam(e, "encrypted", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramEncrypted->type != VAR_DYNAMIC)
var_let(e, paramEncrypted, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, cipher_AES192(e, &p_etat->ctxMod, paramKey, paramPlaintext, paramEncrypted));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromAES192", 10))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramEncrypted = getParam(e, "encrypted", 9);
var * paramPlaintext = getParam(e, "plaintext", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramEncrypted->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, decipher_AES192(e, &p_etat->ctxMod, paramKey, paramEncrypted, paramPlaintext));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "toAES256", 8))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramEncrypted = getParam(e, "encrypted", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramEncrypted->type != VAR_DYNAMIC)
var_let(e, paramEncrypted, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, cipher_AES256(e, &p_etat->ctxMod, paramKey, paramPlaintext, paramEncrypted));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromAES256", 10))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramEncrypted = getParam(e, "encrypted", 9);
var * paramPlaintext = getParam(e, "plaintext", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramEncrypted->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, decipher_AES256(e, &p_etat->ctxMod, paramKey, paramEncrypted, paramPlaintext));
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+468
View File
@@ -0,0 +1,468 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "cipher.h"
#include "string.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ============ PRIVATE ===================================== */
/* donnees utiles a l'algo aes-128 (travaille sur des blocs de 16 octets)
un "mot" (ou word) est un "int" sur 4 octets
avec une cle sur 16 octets, il y a 4 mots (const NK)
et il y a 10 rondes (const NR)
AES-128 : NK = 4, NR = 10
AES-192 : NK = 6, NR = 12 (les blocs sont toujours de 16 octets)
AES-256 : NK = 8, NR = 14 (les blocs sont toujours de 16 octets)
/!\ ici methode aes-ecb : les blocs chiffres sont independamment les uns des autres => pas le mieux !
methode aes-cbc est meilleure : les blocs dependent les uns des autres (le meme bloc present 2 fois sera chiffre differemment - identiques en ecb !)
*/
#define AES_BLOCKSIZE 16
/* le tableau "cle" a une taille de (4*NK)*(NR+1) */
static octet cle128[(4*4)*(10+1)] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, /* la cle est ici, 16 octets */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, /* filler : va etre calcule ensuite */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
static octet cle192[(4*6)*(12+1)] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, /* la cle est ici, 24 octets */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, /* filler : va etre calcule ensuite */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 };
static octet cle256[(4*8)*(14+1)] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, /* la cle est ici, 32 octets */
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,26,27,28,29,30,31,32, /* filler : va etre calcule ensuite */
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32,
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,26,27,28,29,30,31,32 };
/* table utilisee pour la transformation de la cle (expansion), valable pour les les 3 AES 128/192/256 */
static octet rcon[11] = { 0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36 };
/* matrices de substitution utilisee par l'algo : taille 256 */
static octet sbox[256] = { 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 };
static octet inv_sbox[256] = {0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB,
0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB,
0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E,
0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25,
0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x65,0xB6,0x92,
0x6C,0x70,0x48,0x50,0xFD,0xED,0xB9,0xDA,0x5E,0x15,0x46,0x57,0xA7,0x8D,0x9D,0x84,
0x90,0xD8,0xAB,0x00,0x8C,0xBC,0xD3,0x0A,0xF7,0xE4,0x58,0x05,0xB8,0xB3,0x45,0x06,
0xD0,0x2C,0x1E,0x8F,0xCA,0x3F,0x0F,0x02,0xC1,0xAF,0xBD,0x03,0x01,0x13,0x8A,0x6B,
0x3A,0x91,0x11,0x41,0x4F,0x67,0xDC,0xEA,0x97,0xF2,0xCF,0xCE,0xF0,0xB4,0xE6,0x73,
0x96,0xAC,0x74,0x22,0xE7,0xAD,0x35,0x85,0xE2,0xF9,0x37,0xE8,0x1C,0x75,0xDF,0x6E,
0x47,0xF1,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,0x62,0x0E,0xAA,0x18,0xBE,0x1B,
0xFC,0x56,0x3E,0x4B,0xC6,0xD2,0x79,0x20,0x9A,0xDB,0xC0,0xFE,0x78,0xCD,0x5A,0xF4,
0x1F,0xDD,0xA8,0x33,0x88,0x07,0xC7,0x31,0xB1,0x12,0x10,0x59,0x27,0x80,0xEC,0x5F,
0x60,0x51,0x7F,0xA9,0x19,0xB5,0x4A,0x0D,0x2D,0xE5,0x7A,0x9F,0x93,0xC9,0x9C,0xEF,
0xA0,0xE0,0x3B,0x4D,0xAE,0x2A,0xF5,0xB0,0xC8,0xEB,0xBB,0x3C,0x83,0x53,0x99,0x61,
0x17,0x2B,0x04,0x7E,0xBA,0x77,0xD6,0x26,0xE1,0x69,0x14,0x63,0x55,0x21,0x0C,0x7D };
/* table precalculée pour arithmetique sur les polynomes, taille 256 */
static octet mulx2[256] = { 0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,0x1E,
0x20,0x22,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,0x32,0x34,0x36,0x38,0x3A,0x3C,0x3E,
0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,0x52,0x54,0x56,0x58,0x5A,0x5C,0x5E,
0x60,0x62,0x64,0x66,0x68,0x6A,0x6C,0x6E,0x70,0x72,0x74,0x76,0x78,0x7A,0x7C,0x7E,
0x80,0x82,0x84,0x86,0x88,0x8A,0x8C,0x8E,0x90,0x92,0x94,0x96,0x98,0x9A,0x9C,0x9E,
0xA0,0xA2,0xA4,0xA6,0xA8,0xAA,0xAC,0xAE,0xB0,0xB2,0xB4,0xB6,0xB8,0xBA,0xBC,0xBE,
0xC0,0xC2,0xC4,0xC6,0xC8,0xCA,0xCC,0xCE,0xD0,0xD2,0xD4,0xD6,0xD8,0xDA,0xDC,0xDE,
0xE0,0xE2,0xE4,0xE6,0xE8,0xEA,0xEC,0xEE,0xF0,0xF2,0xF4,0xF6,0xF8,0xFA,0xFC,0xFE,
0x1B,0x19,0x1F,0x1D,0x13,0x11,0x17,0x15,0x0B,0x09,0x0F,0x0D,0x03,0x01,0x07,0x05,
0x3B,0x39,0x3F,0x3D,0x33,0x31,0x37,0x35,0x2B,0x29,0x2F,0x2D,0x23,0x21,0x27,0x25,
0x5B,0x59,0x5F,0x5D,0x53,0x51,0x57,0x55,0x4B,0x49,0x4F,0x4D,0x43,0x41,0x47,0x45,
0x7B,0x79,0x7F,0x7D,0x73,0x71,0x77,0x75,0x6B,0x69,0x6F,0x6D,0x63,0x61,0x67,0x65,
0x9B,0x99,0x9F,0x9D,0x93,0x91,0x97,0x95,0x8B,0x89,0x8F,0x8D,0x83,0x81,0x87,0x85,
0xBB,0xB9,0xBF,0xBD,0xB3,0xB1,0xB7,0xB5,0xAB,0xA9,0xAF,0xAD,0xA3,0xA1,0xA7,0xA5,
0xDB,0xD9,0xDF,0xDD,0xD3,0xD1,0xD7,0xD5,0xCB,0xC9,0xCF,0xCD,0xC3,0xC1,0xC7,0xC5,
0xFB,0xF9,0xFF,0xFD,0xF3,0xF1,0xF7,0xF5,0xEB,0xE9,0xEF,0xED,0xE3,0xE1,0xE7,0xE5 };
/* gestion des polynomes */
static octet mulx3(octet x) { return (mulx2[x]^x); }
static octet mulx9(octet x) { return (mulx2[mulx2[mulx2[x]]]^x); }
static octet mulx11(octet x) { return (mulx2[mulx2[mulx2[x]]^x]^x); }
static octet mulx13(octet x) { return (mulx2[mulx2[mulx2[x]^x]]^x); }
static octet mulx14(octet x) { return (mulx2[mulx2[mulx2[x]^x]^x]); }
static void initCleExpansion(env * e, octet * baseKey, octet * key, int NK, int NR)
{
/* copie cle de base dans les cles de rondes */
memcopie(key, baseKey, NK*4);
/* creation des cles de rondes a partir de la cle "de base" */
octet tmp[4], t; /* travail octet par octet */
int n; /* compteur */
for(n = NK*4; n < (4*NK)*(NR+1); n += 4)
{
/* boucle principale de remplissage de la table des cles */
tmp[0] = key[n-4];
tmp[1] = key[n-3];
tmp[2] = key[n-2];
tmp[3] = key[n-1];
if(n % (NK * 4) == 0)
{
/* tous les NK mots, transformation a faire */
/* rotation a gauche de tmp */
t = tmp[0];
tmp[0] = tmp[1];
tmp[1] = tmp[2];
tmp[2] = tmp[3];
tmp[3] = t;
/* application de la transco s-box */
tmp[0] = sbox[tmp[0]];
tmp[1] = sbox[tmp[1]];
tmp[2] = sbox[tmp[2]];
tmp[3] = sbox[tmp[3]];
/* transformation avec les "round constant" */
tmp[0] ^= rcon[n/(4*NK)];
}
else if(NK > 6 && (n % (NK * 4)) == 16)
{
/* AES256 */
tmp[0] = sbox[tmp[0]];
tmp[1] = sbox[tmp[1]];
tmp[2] = sbox[tmp[2]];
tmp[3] = sbox[tmp[3]];
}
key[n] = (key[n-4*NK] ^ tmp[0]);
key[n+1] = (key[n-4*NK+1] ^ tmp[1]);
key[n+2] = (key[n-4*NK+2] ^ tmp[2]);
key[n+3] = (key[n-4*NK+3] ^ tmp[3]);
}
}
void cipher(env * e, octet * cle, int NK, int NR, var * in, var * out)
{
/* chiffrer par blocs de 16 octets (AES_BLOCKSIZE) */
pointeur tIn = in->ptr, tOut;
int r; /* no de ronde */
int n; /* compteur */
octet t0, t1, t2, t3;
int nbblock = in->mLg / AES_BLOCKSIZE, lastblock = 0, cptblock, rest = in->mLg % AES_BLOCKSIZE;
octet pad = AES_BLOCKSIZE - rest; /* <pad> = nb octets ajoutes a la fin, de 1 a 16 (1 a AES_BLOCKSIZE)*/
lastblock = ++nbblock;
/* */
if(dynCtrl(e, out, in->mLg + (ent64)pad, FALSE) != DYN_OK)
return;
tOut = out->ptr;
/* */
for(cptblock = 1; cptblock <= nbblock; cptblock++)
{
if(cptblock == lastblock)
{
for(n = 0; n < rest; n++)
tOut[n] = (tIn[n] ^ cle[n]);
for(n = rest; n < AES_BLOCKSIZE; n++)
tOut[n] = (pad ^ cle[n]);
}
else
/* tInitialisation de la sortie par une transfo "RoundKeyValue" */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = (tIn[n] ^ cle[n]);
/* traitement des NR rondes */
for(r = 1; r <= NR; r++)
{
/* etape "SubBytes" transco s-box */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = sbox[tOut[n]];
/* etape "ShiftRows" : decalage "a gauche" des lignes 2 3 4 de 1 2 3 positions */
t0 = tOut[1];
tOut[1] = tOut[5];
tOut[5] = tOut[9];
tOut[9] = tOut[13];
tOut[13] = t0;
/**/
t0 = tOut[2];
tOut[2] = tOut[10];
tOut[10] = t0;
t0 = tOut[6];
tOut[6] = tOut[14];
tOut[14] = t0;
/**/
t0 = tOut[15];
tOut[15] = tOut[11];
tOut[11] = tOut[7];
tOut[7] = tOut[3];
tOut[3] = t0;
/* etape "MixColumns" sauf derniere ronde */
if(r < NR)
for(n = 0; n < AES_BLOCKSIZE; n+=4)
{
t0 = (mulx2[tOut[n]] ^ tOut[n+3] ^ tOut[n+2] ^ mulx3(tOut[n+1])); /* 2*a0 + a3 + a2 + 3*a1 */
t1 = (mulx2[tOut[n+1]] ^ tOut[n] ^ tOut[n+3] ^ mulx3(tOut[n+2])); /* 2*a1 + a0 + a3 + 3*a2 */
t2 = (mulx2[tOut[n+2]] ^ tOut[n+1] ^ tOut[n] ^ mulx3(tOut[n+3])); /* 2*a2 + a1 + a0 + 3*a3 */
t3 = (mulx2[tOut[n+3]] ^ tOut[n+2] ^ tOut[n+1] ^ mulx3(tOut[n])); /* 2*a3 + a2 + a1 + 3*a0 */
tOut[n] = t0;
tOut[n+1] = t1;
tOut[n+2] = t2;
tOut[n+3] = t3;
}
/* etape "RoundKeyValue" */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] ^= cle[n + r * AES_BLOCKSIZE];
}
tIn += AES_BLOCKSIZE;
tOut += AES_BLOCKSIZE;
}
dynSetLen(e, out, in->mLg + (ent64)pad);
}
void decipher(env * e, octet * cle, int NK, int NR, var * in, var * out)
{
/* dechiffrer par blocs de 16 octets (AES_BLOCKSIZE) */
pointeur tIn = in->ptr, tOut;
if(in->mLg == 0 || in->mLg % AES_BLOCKSIZE != 0)
return; /* chiffre forcement multiple de 16 (AES_BLOCKSIZE) */
if(dynCtrl(e, out, in->mLg, FALSE) != DYN_OK)
return;
tOut = out->ptr;
int r; /* no de ronde */
int n; /* compteur */
octet t0, t1, t2, t3;
int nbblock = in->mLg / (AES_BLOCKSIZE), cptblock;
/* */
for(cptblock = 1; cptblock <= nbblock; cptblock++)
{
/* tInitialisation de la sortie par une transfo "RoundKeyValue" */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = (tIn[n] ^ cle[n + NR * AES_BLOCKSIZE]);
/* traitement des NR rondes */
for(r = NR-1; r >= 0; r--)
{
/* etape "tInvShiftRows" : decalage a droite sur lignes 2 3 4 de 1 2 3 positions */
t0 = tOut[13];
tOut[13] = tOut[9];
tOut[9] = tOut[5];
tOut[5] = tOut[1];
tOut[1] = t0;
/**/
t0 = tOut[2];
tOut[2] = tOut[10];
tOut[10] = t0;
t0 = tOut[6];
tOut[6] = tOut[14];
tOut[14] = t0;
/**/
t0 = tOut[3];
tOut[3] = tOut[7];
tOut[7] = tOut[11];
tOut[11] = tOut[15];
tOut[15] = t0;
/* etape "tInvSubBytes" transco tInv s-box */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = inv_sbox[tOut[n]];
/* etape "RoundKeyValue" */
for(n = 0;n < AES_BLOCKSIZE; n++)
tOut[n] ^= cle[n + r * AES_BLOCKSIZE];
/* etape "tInvMixColumns" sauf derniere ronde */
if(r > 0)
for(n = 0; n < AES_BLOCKSIZE; n+=4)
{
t0 = (mulx14(tOut[n]) ^ mulx9(tOut[n+3]) ^ mulx13(tOut[n+2]) ^ mulx11(tOut[n+1])) ; /* 14*a0 + 9*a3 + 13*a2 + 11*a1 */
t1 = (mulx14(tOut[n+1]) ^ mulx9(tOut[n]) ^ mulx13(tOut[n+3]) ^ mulx11(tOut[n+2])) ; /* 14*a1 + 9*a0 + 13*a3 + 11*a2 */
t2 = (mulx14(tOut[n+2]) ^ mulx9(tOut[n+1]) ^ mulx13(tOut[n]) ^ mulx11(tOut[n+3])) ; /* 14*a2 + 9*a1 + 13*a0 + 11*a3 */
t3 = (mulx14(tOut[n+3]) ^ mulx9(tOut[n+2]) ^ mulx13(tOut[n+1]) ^ mulx11(tOut[n])) ; /* 14*a3 + 9*a2 + 13*a1 + 11*a0 */
tOut[n] = t0;
tOut[n+1] = t1;
tOut[n+2] = t2;
tOut[n+3] = t3;
}
}
tIn += AES_BLOCKSIZE;
tOut += AES_BLOCKSIZE;
}
/* enlever a la longueur finale le padding */
octet pad = out->ptr[in->mLg - 1];
if(pad < 1 || pad > AES_BLOCKSIZE)
pad = 0; /* padding incorrect */
dynSetLen(e, out, in->mLg - (ent64)(pad));
}
/* ============ PUBLIC ===================================== */
WAPIDECL void cipherInit(env * e, modContextCipher * ctx)
{
dynInit(e, &ctx->key, 512);
}
WAPIDECL void cipherEnd(env * e, modContextCipher * ctx)
{
dynFree(e, &ctx->key);
}
WAPIDECL long cipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*4)*(10+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*4)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle128, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 4, 10); /* cle128 */
cipher(e, ctx->key.ptr, 4, 10, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long cipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*6)*(12+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*6)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle192, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 6, 12); /* cle192 */
cipher(e, ctx->key.ptr, 6, 12, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long cipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*8)*(14+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*8)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle256, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 8, 14); /* cle256 */
cipher(e, ctx->key.ptr, 8, 14, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long decipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*4)*(10+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*4)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle128, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 4, 10); /* cle128 */
decipher(e, ctx->key.ptr, 4, 10, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long decipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*6)*(12+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*6)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle192, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 6, 12); /* cle192 */
decipher(e, ctx->key.ptr, 6, 12, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long decipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*8)*(14+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*8)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle256, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 8, 14); /* cle256 */
decipher(e, ctx->key.ptr, 8, 14, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
+37 -10
View File
@@ -8,8 +8,10 @@ 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 -c w_src/rep.c -s -Wall -DUNIX -m64 -fPIC -o exec/rep.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.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
gcc -c w_src/lex.c -s -Wall -DUNIX -m64 -fPIC -o exec/lexw.o
gcc -c w_src/convert.c -s -Wall -DUNIX -m64 -fPIC -o exec/convert.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o exec/lexw.o exec/convert.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/lexw.o exec/convert.o
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
@@ -21,13 +23,22 @@ echo 3. Compilation de sockMod.c
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
echo 3b. Compilation de securesockMod.c
gcc -shared -s -o exec/securesock_lib.so w_src/securesock_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -lssl -lcrypto -l:sock_lib.so
gcc -shared -s -o exec/securesock.o w_src/securesockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:securesock_lib.so
echo 3c. Compilation de sshMod.c
gcc -shared -s -o exec/wssh_lib.so w_src/ssh_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -lssl -lcrypto -lssh
gcc -shared -s -o exec/wssh.o w_src/sshMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:wssh_lib.so
#echo 4. Compilation de sqlite
#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
#gcc -shared -s -o exec/libsqlite3.so w_src/sqlite3.c -m64 -fPIC -lpthread -ldl -lm
gcc -shared -s -o exec/sqlite_lib.so w_src/sqlite_lib.c -m64 -DUNIX -Wall -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 4. Compilation de convdMod.c
gcc -shared -s -o exec/conv.o w_src/convMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 5. Compilation de lzwMod.c
gcc -shared -s -o exec/lzw_lib.so w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
@@ -49,7 +60,12 @@ 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
echo 8. Compilation de hashMod.c
gcc -shared -s -o exec/hash.o w_src/hashMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/hash_lib.so w_src/hash_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/hash.o w_src/hashMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:hash_lib.so
echo 8b. Compilation de cipherMod.c
gcc -shared -s -o exec/cipher_lib.so w_src/cipher_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/cipher.o w_src/cipherMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:cipher_lib.so
echo 9. Compilation de systemMod.c
gcc -shared -s -o exec/system.o w_src/systemMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
@@ -57,11 +73,22 @@ gcc -shared -s -o exec/system.o w_src/systemMod.c -m64 -DUNIX -Wall -fPIC -L./ex
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 10b. Compilation de lexMod.c
gcc -shared -s -o exec/lex.o w_src/lexMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 10c. Compilation de fastcgi/http/raw/websocket
gcc -shared -s -o exec/raw_lib.so w_src/raw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/fcgi_lib.so w_src/fcgi_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/http_lib.so w_src/http_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/websocket_lib.so w_src/websocket_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/http.o w_src/httpMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:http_lib.so
gcc -shared -s -o exec/fcgi.o w_src/fcgiMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:fcgi_lib.so
echo 11. Compilation et link de langage.c
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
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 -l:lzw_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
gcc w_src/assembler.c -s -o exec/lwa -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:lzw_lib.so
echo 13. Generation du formatteur de code
gcc w_src/format.c -s -o exec/lwf -Wall -m64 -DUNIX -L./exec -l:libw.so
@@ -72,7 +99,7 @@ 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 \(compilateur w\)
gcc w_src/genw.c -s -o exec/lwc -Wall -m64 -DUNIX -Wno-stringop-truncation -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_utf => gcc test_utf.c -s -o utf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:lzw_lib.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 "package => dpkg-deb --build wlanguage"
+55 -25
View File
@@ -7,67 +7,97 @@ cd "C:\Users\Poupougne42\source\repos\win_w_src"
echo ------------------------------------------------------------------------------------------
echo 0. Compilation pour dynamic lib DLL
cl /LD /DWINLIB /DWAPIEXPORT /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
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 w_src\convert.c /DEBUG:NONE
echo 1a. Compilation de templateMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\template.dll w_src\templateMod.c exec\libw.lib
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 /Feexec\file.dll w_src\fileMod.c exec\libw.lib
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 /Feexec\time.dll w_src\timeMod.c exec\libw.lib
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 /Feexec\hash.dll w_src\hashMod.c exec\libw.lib
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\hash_lib.dll w_src\hash_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\hash.dll w_src\hashMod.c exec\libw.lib exec\hash_lib.lib /DEBUG:NONE
echo 1e. Compilation de systemMod.c (ws2_32.lib pour socket)
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\system.dll w_src\systemMod.c exec\libw.lib ws2_32.lib advapi32.lib
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 /Feexec\random.dll w_src\randomMod.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\random.dll w_src\randomMod.c exec\libw.lib /DEBUG:NONE
echo 1g. Compilation de cipherMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\cipher_lib.dll w_src\cipher_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\cipher.dll w_src\cipherMod.c exec\libw.lib exec\cipher_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 2a. Compilation de jsonMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\json_lib.dll w_src\json_lib.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib
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 /Feexec\shm_lib.dll w_src\shm_lib.c exec\libw.lib advapi32.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\shm.dll w_src\shmMod.c exec\libw.lib exec\shm_lib.lib
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 /Feexec\lzw_lib.dll w_src\lzw_lib.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\lzw.dll w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib
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 /Feexec\pdf_lib.dll w_src\pdf_lib.c exec\libw.lib exec\lzw_lib.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\pdf.dll w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib
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 /Feexec\sock_lib.dll w_src\sock_lib.c exec\libw.lib ws2_32.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\sock.dll w_src\sockMod.c exec\libw.lib exec\sock_lib.lib ws2_32.lib
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 /Feexec\encod_lib.dll w_src\encod_lib.c exec\libw.lib
rem cl /LD /DWINLIB /DWAPIIMPORT /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib
echo 2eb. Compilation de securesockMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\securesock_lib.dll w_src\securesock_lib.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" libssl.lib libcrypto.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\securesock.dll w_src\securesockMod.c exec\libw.lib exec\sock_lib.lib exec\securesock_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include"
echo 2ec. Compilation de sshMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\wssh_lib.dll w_src\ssh_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" ssh.lib libssl.lib libcrypto.lib z.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\wssh.dll w_src\sshMod.c exec\libw.lib exec\wssh_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" ssh.lib libssl.lib libcrypto.lib z.lib
echo 2f. Compilation de convMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\conv.dll w_src\convMod.c exec\libw.lib /DEBUG:NONE
echo 2g. Compilation de lexMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lex.dll w_src\lexMod.c exec\libw.lib /DEBUG:NONE
echo 2h. Compilation de fcgi.c/http.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\raw_lib.dll w_src\raw_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\fcgi_lib.dll w_src\fcgi_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\http_lib.dll w_src\http_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\websocket_lib.dll w_src\websocket_lib.c exec\libw.lib exec\hash_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\http.dll w_src\httpMod.c exec\libw.lib exec\http_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\fcgi.dll w_src\fcgiMod.c exec\libw.lib exec\fcgi_lib.lib /DEBUG:NONE
echo 2i. Compilation de sqlite
cl /LD /Gy /MD /Feexec\sqlite3.dll w_src\sqlite3.c /DSQLITE_API=__declspec(dllexport) /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sqlite_lib.dll w_src\sqlite_lib.c exec\libw.lib exec\sqlite3.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 3a. Generation lw.exe
cl w_src\langage.c /DWINLIB /DWAPIIMPORT /Feexec\lw.exe exec\libw.lib exec\shm_lib.lib advapi32.lib /link
cl w_src\langage.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lw.exe exec\libw.lib exec\shm_lib.lib exec\lzw_lib.lib advapi32.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3b. Generation lwa.exe
cl w_src\assembler.c /DWINLIB /DWAPIIMPORT /Feexec\lwa.exe exec\libw.lib /link
cl w_src\assembler.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwa.exe exec\libw.lib exec\lzw_lib.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3c. Generation lwc.exe
cl w_src\genw.c /DWINLIB /DWAPIIMPORT /Feexec\lwc.exe exec\libw.lib /link
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 /Feexec\lwf.exe exec\libw.lib /link
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 /Feexec\wlex.exe exec\libw.lib /link
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
+231
View File
@@ -0,0 +1,231 @@
/* **********************************************
__ __ __
\ \/ \/ / 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"
/* ============================================================================================= */
#include "convert.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_CONVFMT = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Conversion error, bad character"
};
/* ============================================================================================= */
#include "mod.c"
#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 */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toHexa", 6))
{
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHexadecimal = getParam(e, "hexadecimal", 11);
if(paramPlaintext == NULL || paramHexadecimal == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramHexadecimal->type != VAR_DYNAMIC)
var_let(e, paramHexadecimal, &e->int_dynamic, FALSE, FALSE);
if(str2hex(e, paramPlaintext, paramHexadecimal) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromHexa", 8))
{
/* get param in the right order */
var * paramHexadecimal = getParam(e, "hexadecimal", 11);
var * paramPlaintext = getParam(e, "plaintext", 9);
if(paramHexadecimal == NULL || paramPlaintext == NULL)
exc = EX_MODPARAM;
else if(paramHexadecimal->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
if(hex2str(e, paramHexadecimal, paramPlaintext) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "toBase64", 8))
{
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramBase64encoded = getParam(e, "base64encoded", 13);
if(paramPlaintext == NULL || paramBase64encoded == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramBase64encoded->type != VAR_DYNAMIC)
var_let(e, paramBase64encoded, &e->int_dynamic, FALSE, FALSE);
if(str2base64(e, paramPlaintext, paramBase64encoded) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromBase64", 10))
{
/* get param in the right order */
var * paramBase64encoded = getParam(e, "base64encoded", 13);
var * paramPlaintext = getParam(e, "plaintext", 9);
if(paramBase64encoded == NULL || paramPlaintext == NULL)
exc = EX_MODPARAM;
else if(paramBase64encoded->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
if(base642str(e, paramBase64encoded, paramPlaintext) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+71 -28
View File
@@ -20,7 +20,13 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "encod.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "langage.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
@@ -53,7 +59,6 @@ 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 };
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,
@@ -92,8 +97,8 @@ WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat)
/* 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];
resultat->ptr[to--] = carhex[this->ptr[from] % 16];
resultat->ptr[to--] = carhex[this->ptr[from--] / 16];
}
dynSetLen(e, resultat, this->mLg * 2);
return DYN_OK;
@@ -127,26 +132,26 @@ WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat)
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[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[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[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4) | (this->ptr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->ptr[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];
resultat->mPtr[to++] = carBase64[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4) | (this->ptr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->ptr[from + 1] & 15) << 2) | (this->ptr[from + 2] >> 6)];
resultat->mPtr[to++] = carBase64[this->ptr[from + 2] & 63];
}
}
/* */
@@ -170,9 +175,12 @@ WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat)
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)
if((c1 = hexa[this->ptr[from]]) == -1 || (c2 = hexa[this->ptr[from + 1]]) == -1)
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* erreur format hexa incorrect */
resultat->mPtr[to++] = (c1 << 4) | c2;
}
resultat->ptr[to++] = (c1 << 4) | c2;
}
dynSetLen(e, resultat, this->mLg / 2);
return DYN_OK;
@@ -199,28 +207,34 @@ WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat)
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]];
char c1 = base64[this->ptr[from]];
char c2 = base64[this->ptr[from + 1]];
char c3 = base64[this->ptr[from + 2]];
char c4 = base64[this->ptr[from + 3]];
if(c1 == -1 || c2 == -1 || c3 == -1 || c4 == -1 || c1 == 99 || c2 == 99 || (c3 == 99 && c4 != 99))
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* erreur format base64 incorrect */
}
if(c4 == 99 && from + 4 < this->mLg)
{
dynSetLen(e, resultat, 0);
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;
resultat->ptr[to] = 0;
resultat->ptr[to + 1] = 0;
resultat->ptr[to + 2] = 0;
resultat->ptr[to] = c1 << 2;
resultat->ptr[to] |= c2 >> 4;
if(c3 != 99)
{
resultat->mPtr[to + 1] = (c2 & 15) << 4;
resultat->mPtr[to + 1] |= c3 >> 2;
resultat->ptr[to + 1] = (c2 & 15) << 4;
resultat->ptr[to + 1] |= c3 >> 2;
if(c4 != 99)
{
resultat->mPtr[to + 2] = (c3 & 3) << 6;
resultat->mPtr[to + 2] |= c4;
resultat->ptr[to + 2] = (c3 & 3) << 6;
resultat->ptr[to + 2] |= c4;
}
else
lgClair--;
@@ -231,3 +245,32 @@ WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat)
dynSetLen(e, resultat, lgClair);
return DYN_OK;
}
WAPIDECL void str2upper(env * e, Dynamic * this)
{
long i;
for(i = 0; i < this->mLg; i++)
if(this->mPtr[i] >= 'a' && this->mPtr[i] <= 'z')
this->mPtr[i] -= 32;
}
WAPIDECL void str2lower(env * e, Dynamic * this)
{
long i;
for(i = 0; i < this->mLg; i++)
if(this->mPtr[i] >= 'A' && this->mPtr[i] <= 'Z')
this->mPtr[i] += 32;
}
WAPIDECL ent64s hex2num(env * e, Dynamic * this)
{
ent64s resultat = 0;
char c;
long i;
for(i = 0; i < this->mLg; i++)
if((c = hexa[this->ptr[i]]) == -1)
break; // erreur hexa : fin de la conversion
else
resultat = (resultat << 4) + (ent64s)c;
return resultat;
}
+7 -7
View File
@@ -20,17 +20,17 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#ifndef CONVERT_H
#define CONVERT_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);
WAPIDECL void str2upper(env * e, Dynamic * this);
WAPIDECL void str2lower(env * e, Dynamic * this);
WAPIDECL ent64s hex2num(env * e, Dynamic * this);
#endif
+31 -17
View File
@@ -77,12 +77,20 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
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 le faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
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 */
@@ -97,39 +105,45 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
memset(p_etat->base, 0, LGNOMBASE + 1);
p_etat->ctx = NULL;
p_etat->fnDb = NULL;
//
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
//*** code specifique ici
}
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 == 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(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
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
+28 -23
View File
@@ -60,26 +60,20 @@ char * strerr[] = {
"EX_REMOVE_KO remove field error",
"EX_CHILD_FORK cannot fork process",
"EX_CHILD_EXEC cannot run new process",
"EX_ZERO_FOR_INCR foreach increment is zero" // 40
"EX_ZERO_FOR_INCR foreach increment is zero", // 40
"EX_SORTEDSEARCH_KO sort type incorrect",
"EX_SQRT_NEG square root of a negative number is not calculated.",
"EX_INT_EXP Fractional exponentiation is not calculated",
"EX_VARPARAM_KO Null parameter pointer",
"EX_PARAM_NOTFOUND Named parameter not found", // 45
"EX_NUMOVF Numeric overflow",
"EX_INPUT_TTY Cannot read from terminal or stdin"
};
enum {
cLF = 10
};
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, cLF);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, cLF, ',', 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;
}
/*
blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,identnext,8,reste,9
*/
@@ -103,7 +97,17 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
void print_var(env * e, var * v, Dynamic * tmp, int prettyPrint)
{
if(v->type == VAR_PARAM)
{
v = (var *)v->ptr; /* travailler avec la var pointee */
if(v == NULL)
{
if(e->demon)
dynPrintfSz(e, "Null parameter pointer\n", NULL);
else
printf("Null parameter pointer\n");
return;
}
}
//
char * var_str[9] = {"0","X","N","S","P","D","H","O","B"};
if(e->demon)
@@ -164,7 +168,7 @@ void print_var(env * e, var * v, Dynamic * tmp, int prettyPrint)
dynPrintfHex(e, PRINTF_MARK ")\n", (ent64)v->ptr, 0); // S
break;
case VAR_PARAM:
dynPrintfSz(e, "Var " PRINTF_MARK "\n", var_str[v->type]); // P : mais ne peut pas arriver ici
dynPrintfSz(e, "Var " PRINTF_MARK "\n", var_str[v->type]); // P : mais ne peut pas arriver ici normalement (VAR_PARAM de VAR_PARAM non gere)
break;
}
else
@@ -216,7 +220,7 @@ void print_var(env * e, var * v, Dynamic * tmp, int prettyPrint)
printf("Var %c : %p (-> %p)\n",e->var_car[v->type], v, v->ptr); // S
break;
case VAR_PARAM:
printf("Var %c\n",e->var_car[v->type]); // P : mais ne peut pas arriver ici
printf("Var %c\n",e->var_car[v->type]); // P : mais ne peut pas arriver ici normalement (VAR_PARAM de VAR_PARAM non gere)
break;
}
}
@@ -369,6 +373,7 @@ void debug(env * e)
dynPrintfInt64(e, "W" PRINTF_MARK, VERSION, 0);
if( ! srcFound)
dynPrintfInt64(e, ":" PRINTF_MARK, e->ligsrc, 0);
dynPrintfInt64(e, "!" PRINTF_MARK, e->except_ex, 0);
dynPrintfSz(e, "> ", NULL);
writeShm(e, (modContextShm *)e->debugCtxShm);
//
@@ -392,9 +397,9 @@ void debug(env * e)
{
// prompt
if(srcFound)
printf("W%d> ", VERSION);
printf("W%d!%lld> ", VERSION, e->except_ex);
else
printf("W%d:%lld> ", VERSION, e->ligsrc);
printf("W%d:%lld!%lld> ", VERSION, e->ligsrc, e->except_ex);
dynSetLen(e, &e->debugcmd, 0);
int c;
char cmd[2];
@@ -471,7 +476,7 @@ void debug(env * e)
}
/* trt cmd ; e->debugcmd sert de variable tmp ici */
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X");
hex2str(e, &tmp, &e->debugcmd);
if(dynCompare(e, &e->debugcmd, CMP_EQ, "vg", 2) || dynCompare(e, &e->debugcmd, CMP_EQ, "VG", 2))
{
/* voir le contenu d'une variable */
@@ -498,7 +503,7 @@ void debug(env * e)
break;
}
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X");
hex2str(e, &tmp, &e->debugcmd);
if(e->debugcmd.mLg < 2 || e->debugcmd.mLg > 24)
{
if(e->demon)
@@ -673,7 +678,7 @@ void debug(env * e)
else
{
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X"); // e->debugcmd = numLigne
hex2str(e, &tmp, &e->debugcmd); // e->debugcmd = numLigne
long numLigne = dynToNum(e, &e->debugcmd, FALSE, 9);
long pos = dynSortLocateSz(e, &e->debugbrkpoint, Int64ToSz(e, numLigne, FALSE, 9), cFM, DYN_SORT_ASC, DYN_NONE, DYN_NONE);
if(pos < 0 && tok == r.ajouter)
@@ -736,7 +741,7 @@ void debug(env * e)
break;
}
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X");
hex2str(e, &tmp, &e->debugcmd);
if(e->debugcmd.mLg < 2 || e->debugcmd.mLg > 24)
{
if(e->demon)
@@ -761,7 +766,7 @@ void debug(env * e)
{
hashtable_do(e, HASH_READ, e->local, e->nom, &vnext);
}
if(v == NULL)
if(vnext == NULL)
{
/* si pas trouve (ou pas de locale), cherche dans la hash "globale" */
hashtable_do(e, HASH_READ, &e->g, e->nom, &vnext);
+262 -411
View File
@@ -321,6 +321,28 @@ WAPIDECL long dynCtrl(env * e, Dynamic * this, long lg, long copier)
return DYN_OK;
}
WAPIDECL long dynResize(env * e, Dynamic * this, long lgmax)
{
if(this->mPtr == NULL)
return DYN_ERR;
if(lgmax < DYN_LGMIN)
lgmax = DYN_LGMIN;
if(this->mLgmax != lgmax)
{
char * tmp = (char *)memalloc(e, lgmax);
if(tmp == NULL)
return DYN_ERR;
memfree(e, this->mPtr);
this->mLgmax = lgmax;
this->mPtr = tmp;
}
/* raz dynamic */
this->mLg = 0;
this->mPtr[0] = 0;
this->mInternal = 0;
return DYN_OK;
}
WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg)
{
/* UTF8 lg physique ici */
@@ -1310,6 +1332,8 @@ WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp
}
/* chercher le sousChamp */
nSep = 1;
if(numSousChamp == 0 && (this->mPtr[iPos + 1] == separateurChamp || iPos + 1 == this->mLg))
nSep = 0; // si champ vide et sous-champ no 1, ne pas ajouter de marque de sous-champ a la fin
for(iScan = iPos + 1; numSousChamp > 0 && iScan < this->mLg; iScan++)
if(this->mPtr[iScan] == separateurSousChamp)
{
@@ -1318,9 +1342,9 @@ WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp
}
else if(this->mPtr[iScan] == separateurChamp)
{
iPos = iScan - 1;
nSep = 0;
break;
iPos = iScan - 1;
nSep = 0;
break;
}
else if(iScan == this->mLg - 1)
{
@@ -2424,414 +2448,6 @@ WAPIDECL long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * rempl
return DYN_OK;
}
WAPIDECL char * dynConvertCharToCharHexa(octet c)
{
static char car[16] = {"0123456789ABCDEF"};
static char res[3] = {0};
res[0] = car[c / 16];
res[1] = car[c % 16];
return res;
}
// dynOconv ne sert pas, à gérer ailleurs autrement : faire un module Convert : Hexa, base64 ; horodate a deja son module
WAPIDECL long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format)
{
/* a revoir pour UTF8 ? (Base64 ?) oui pour D car d'autres cars utf8 peuvent etre dans la chaine */
static char car[64] = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_."}; /* sert a la conv hexa et base64 */
char tmp[5], * chaine;
long lg, i;
//
chaine = this->mPtr;
lg = this->mLg;
switch(*format++)
{
case 'D': // obsolete ? utiliser le mod Horodate
{
struct tm * ptm;
/* conversion date/heure : format interne = time_t unix sur 32 bits */
time_t tm;
if(this->mLg == 0)
{
tm = time(NULL);
ptm = gmtime(&tm);
}
else
{
tm = dynToNum(e, this, DYN_NONE, 10); /* pas de signe, lg max sur 32 bits = 10 chiffres */
if(this->mInternal == DYN_ERR)
return DYN_ERR; /* pbm de conversion numerique */
ptm = localtime(&tm);
}
/* analyse formatage demande */
dynLet(e, resultat, NULL, DYN_LGNONE);
tmp[1] = 0;
while((tmp[0] = *format++))
switch(tmp[0])
{
case 'Y':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_year + 1900, DYN_NONE, 4), 4);
break;
case 'y':
dynConcatSz(e, resultat, Int32ToSz((ptm->tm_year + 1900) % 100, DYN_NONE, 2), 2);
break;
case 'M':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mon + 1, DYN_NONE, 2), 2);
break;
case 'D':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mday, DYN_NONE, 2), 2);
break;
case 'h':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_hour, DYN_NONE, 2), 2);
break;
case 'm':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_min, DYN_NONE, 2), 2);
break;
case 's':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_sec, DYN_NONE, 2), 2);
break;
default:
dynConcatSz(e, resultat, tmp, 1);
break;
}
break;
}
/* */
case 'H':
/* uniquement heure (0-86399) */
break;
/* */
case 'X':
/* conversion en hexa de toute la chaine */
tmp[2] = 0;
if(dynCtrl(e, resultat, lg * 2, DYN_FALSE)) /* chaine hexa : taille double de celle origine */
return DYN_ERR;
for(i = 0; i < lg; i++)
{
tmp[0] = car[chaine[i] / 16];
tmp[1] = car[chaine[i] % 16];
dynConcatSz(e, resultat, tmp, 2);
}
break;
/* */
case 'B':
/* conversion en base64 avec "_." comme 2 derniers cars et sans "=" a la fin (pas le "vrai" base64) */
/* 3 cars en clair en donne 4 en base 64 ; si le dernier bloc contient 2 cars, la sortie est de 3 cars */
/* si le dernier bloc contient 1 car, la sortie est de 2 cars (padding avec des bits a 0) */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
tmp[4] = 0;
if(dynCtrl(e, resultat, lg + lg / 3 + 4, DYN_FALSE)) /* chaine base64 : taille + 1/3 de la taile originale (+4 est une sécurité) */
return DYN_ERR;
for(i = 0; i < lg; i += 3)
{
if(i+1 >= lg)
{
/* bloc de 1 octet => 2 cars en sortie */
tmp[0] = car[chaine[i] >> 2];
tmp[1] = car[((chaine[i] & 3) << 4)];
tmp[2] = 0;
/* */
} else if(i+2 >= lg)
{
/* bloc de 2 octets => 3 cars en sortie */
tmp[0] = car[chaine[i] >> 2];
tmp[1] = car[((chaine[i] & 3) << 4) | (chaine[i+1] >> 4)];
tmp[2] = car[((chaine[i+1] & 15) << 2)];
tmp[3] = 0;
}
else
{
/* bloc de 3 octets => 4 cars en sortie */
tmp[0] = car[chaine[i] >> 2];
tmp[1] = car[((chaine[i] & 3) << 4) | (chaine[i+1] >> 4)];
tmp[2] = car[((chaine[i+1] & 15) << 2) | (chaine[i+2] >> 6)];
tmp[3] = car[chaine[i+2] & 63];
}
dynConcatSz(e, resultat, tmp, 4);
}
break;
}
return DYN_OK;
}
// seul dynIconv "X" sert dans w : ç gérer ailleurs et autrement
WAPIDECL long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format)
{
/* a revoir pour UTF8 ? (Base64 ?) */
static char car[64] = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_."}; /* sert a la conv hexa et base64 */
char tmp[5], * chaine, c1, c2, c3, c4;
long lg, i, conv_ok, h, b, valeur;
/* */
chaine = this->mPtr;
lg = this->mLg;
switch(*format++)
{
case 'D':
{
struct tm stm;
stm.tm_year = - 1900;
stm.tm_mon = - 1;
stm.tm_mday = 0;
stm.tm_hour = 0;
stm.tm_min = 0;
stm.tm_sec = 0;
stm.tm_isdst = -1;
/* conversion date/heure : format interne = time_t unix sur 32 bits */
while((c1 = *format++))
switch(c1)
{
case 'Y':
if(lg < 4)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 1000;
valeur += ((*chaine++) - 48) * 100;
valeur += ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 4;
stm.tm_year += valeur;
break;
case 'y':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
if(valeur > 35)
valeur += 1900;
else
valeur += 2000;
lg -= 2;
stm.tm_year += valeur;
break;
case 'M':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_mon += valeur;
break;
case 'D':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_mday += valeur;
break;
case 'h':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_hour += valeur;
break;
case 'm':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_min += valeur;
break;
case 's':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_sec += valeur;
break;
default:
chaine++;
break;
}
if((valeur = mktime(&stm)) == -1)
return DYN_ERR;
/* */
dynLet(e, resultat, NULL, DYN_LGNONE);
dynConcatSz(e, resultat, Int32ToSz(valeur, DYN_NONE, DYN_NONE), DYN_LGNONE); /* non signe, pas de padding ; longueur pas connue */
break;
/* */
}
case 'H':
/* uniquement heure (0-86399) */
break;
/* */
case 'X':
/* conversion en clair de la chaine en hexa */
tmp[1] = 0;
if(dynCtrl(e, resultat, lg / 2 + 1, DYN_FALSE))
return DYN_ERR;
for(i = 0; i < lg; i += 2)
{
conv_ok = DYN_FALSE;
c1 = chaine[i];
c2 = chaine[i + 1]; /* si impair, c2 est le \0 de fin de chaine... */
for(h = 0; h < 16 && !conv_ok; h++)
if(c1 == car[h])
{
tmp[0] = h << 4; /* fois 16 */
for(h = 0; h < 16; h++)
if(c2 == car[h])
{
tmp[0] |= h;
dynConcatSz(e, resultat, tmp, 1);
conv_ok = DYN_TRUE;
break;
}
}
if(!conv_ok)
return DYN_ERR;
}
break;
/* */
case 'B':
/* conversion en clair de la chaine en base64 avec "_." comme 2 derniers cars et sans "=" a la fin (pas le "vrai" base64) */
/* multiple de 4 => bloc de 4 donne 3 cars en clair ; bloc de 3 donne 2 en clair ; bloc de 2 donne 1 en clair */
/* bloc de 1 est une erreur : ne sera pas traite */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
tmp[3] = 0;
if(dynCtrl(e, resultat, lg - lg / 4 + 4, DYN_FALSE))
return DYN_ERR;
for(i = 0; i < lg; i += 4)
{
conv_ok = DYN_FALSE;
c1 = chaine[i];
if(i + 1 >= lg)
{
/* bloc de 1 octet => erreur et arret du decodage */
/* */
} else if(i + 2 >= lg)
{
/* bloc de 2 octets => 1 car en clair */
c2 = chaine[i + 1];
for(b = 0; b < 64 && !conv_ok; b++)
if(c1 == car[b])
{
tmp[0] = b << 2;
for(b = 0; b < 64; b++)
if(c2 == car[b])
{
tmp[0] |= b >> 4;
tmp[1] = 0;
dynConcatSz(e, resultat, tmp, 1);
conv_ok = DYN_TRUE;
break;
}
}
/* */
} else if(i + 3 >= lg)
{
/* bloc de 3 octets => 2 cars en clair */
c2 = chaine[i + 1];
c3 = chaine[i + 2];
for(b = 0; b < 64 && !conv_ok; b++)
if(c1 == car[b])
{
tmp[0] = b << 2;
for(b = 0; b < 64 && !conv_ok; b++)
if(c2 == car[b])
{
tmp[0] |= b >> 4;
tmp[1] = (b & 15) << 4;
for(b = 0; b < 64; b++)
if(c3 == car[b])
{
tmp[1] |= b >> 2;
tmp[2] = 0;
dynConcatSz(e, resultat, tmp, 2);
conv_ok = DYN_TRUE;
break;
}
}
}
}
else
{
/* bloc de 4 octets => 3 cars en clair */
c2 = chaine[i + 1];
c3 = chaine[i + 2];
c4 = chaine[i + 3];
for(b = 0; b < 64 && !conv_ok; b++)
if(c1 == car[b])
{
tmp[0] = b << 2;
for(b = 0; b < 64 && !conv_ok; b++)
if(c2 == car[b])
{
tmp[0] |= b >> 4;
tmp[1] = (b & 15) << 4;
for(b = 0; b < 64 && !conv_ok; b++)
if(c3 == car[b])
{
tmp[1] |= b >> 2;
tmp[2] = (b & 3) << 6;
for(b = 0; b < 64; b++)
if(c4 == car[b])
{
tmp[2] |= b;
dynConcatSz(e, resultat, tmp, 3);
conv_ok = DYN_TRUE;
break;
}
}
}
}
}
if(!conv_ok)
return DYN_ERR;
}
break;
}
return DYN_OK;
}
// mettre ailleurs ? module convert ?
WAPIDECL long dynConvertHexaToLong(Dynamic * valeur)
{
static long hexa[128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
//
long resultat = 0;
for(long cptCar = 0; cptCar < valeur->mLg; cptCar++)
resultat = (resultat * 16) + hexa[valeur->mPtr[cptCar] & 127];
return resultat;
}
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c)
{
static char hexa[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128 cars a la fin de cette ligne */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
if((hexa[(unsigned char)c1] == 0 && c1 != '0') || (hexa[(unsigned char)c2] == 0 && c2 != '0'))
return DYN_ERR; // erreur format hexa incorrect
*c = hexa[(unsigned char)c1] * 16 + hexa[(unsigned char)c2];
return DYN_OK;
}
WAPIDECL long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg)
{
/* a revoir pour UTF8, cf. dynFmtUtf8 */
@@ -3058,6 +2674,54 @@ WAPIDECL long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadr
return DYN_OK;
}
WAPIDECL void dynTrimSpace(env * e, Dynamic * this)
{
char * lire;
char * ecrire;
int etat = 0; /* 0 = debut chaine, 1 = milieu et fin, 2 = milieu et fin avec un espace ecrit */
/* trim de la chaine : enleve les <car> en debut et fin de chaine, au "milieu" en laisse un seul */
lire = this->mPtr;
ecrire = this->mPtr;
/* */
while(*lire != 0)
switch(etat)
{
case 0:
/* debut de chaine */
if(*lire == 32)
lire++;
else
{
*ecrire++ = *lire++;
etat = 1;
}
break;
case 1:
/* milieu/fin de chaine */
if(*lire == 32)
{
etat = 2;
}
*ecrire++ = *lire++;
break;
case 2:
/* milieu/fin de chaine avec un espace ecrit */
if(*lire == 32)
lire++;
else
{
*ecrire++ = *lire++;
etat = 1;
}
break;
}
if(etat == 2)
{
ecrire--;
}
dynSetLen(e, this, ecrire - this->mPtr);
}
WAPIDECL long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option)
{
/* a revoir pour UTF8, cf. dynTrimUtf8 */
@@ -3170,4 +2834,191 @@ WAPIDECL long dynTrimUtf8(env * e, Dynamic * this, Dynamic * resultat, char * ca
return DYN_OK;
}
WAPIDECL void dynCut(env * e, Dynamic * this, long pos)
{
/* le car situe a <position> est le premier garde */
if (pos <= 0 || this->mLg < 1)
return;
if(pos >= this->mLg)
{
// position de cut superieure a la longueur de la chaine : on vide la chaine
this->mLg = 0;
this->mPtr[this->mLg] = 0;
return;
}
long lg = this->mLg - pos;
memcopie(this->mPtr, this->mPtr + pos, lg);
this->mLg = lg;
this->mPtr[this->mLg] = 0;
}
WAPIDECL long dynCleanString(env * e, Dynamic * this, octet debutGarde, octet finGarde, long convHexa)
{
/* nettoie la chaine <this> des octets dont le code ascii n'est PAS dans [debutGarde, finGarde]
convHexa : FALSE pour supprimer et ne pas convertir en hexa #xx, TRUE garder le car et mis en hexa #xx
*/
if(this == NULL || debutGarde > finGarde)
return DYN_ERR;
if(this->mLg == 0)
return DYN_OK;
/* */
if(convHexa)
{
long scan = 0, lgc = 1, lgr = 3;
do
{
if(this->mPtr[scan] >= debutGarde && this->mPtr[scan] <= finGarde)
scan++;
else
{
// repris de dynChange, quand remplace est plus grand que cherchee : insertion de 2 cars
// car remplace par # et insertion du code ascii (remplace 1 octet (lgc) par 3 octets (lgr))
// scan = pos_p ( => p - this->mPtr )
if(dynCtrl(e, this, this->mLg + lgr - lgc, DYN_TRUE))
return DYN_ERR; // erreur memoire
char * p = this->mPtr + scan;
//
// deplacement depuis la fin
long n = this->mLg - scan - lgc + 1; // +1 pour copier le \0 de fin...
memcopie(p + lgr, p + lgc, n);
//
char * hex = dynConvertCharToCharHexa((octet)(*p));
*p++ = '#';
*p++ = hex[0];
*p++ = hex[1];
//
this->mLg += (lgr - lgc);
scan += lgr;
}
} while (scan < this->mLg);
/* this->mLg et 0 de fin deja a jour */
this->mPtr[this->mLg] = 0;
}
else
{
/* equivalent a dynErase sur octets hors de la plage de codes ASCII, PAS de gestion UTF8 ici, uniquement octets */
long i, pos = 0;
for(i = 0; i < this->mLg; i++)
{
if(this->mPtr[i] >= debutGarde && this->mPtr[i] <= finGarde)
{
if(pos != i) /* pour ne pas recopier les premiers caracteres quand pas de suppression */
this->mPtr[pos++] = this->mPtr[i];
else
pos++;
}
}
this->mLg = pos;
this->mPtr[this->mLg] = 0;
}
return DYN_OK;
}
WAPIDECL char * dynConvertCharToCharHexa(octet c)
{
static char car[16] = {"0123456789ABCDEF"};
static char res[3] = {0};
res[0] = car[c / 16];
res[1] = car[c % 16];
return res;
}
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c)
{
static char hexa[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128 cars a la fin de cette ligne */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
if((hexa[(unsigned char)c1] == 0 && c1 != '0') || (hexa[(unsigned char)c2] == 0 && c2 != '0'))
return DYN_ERR; // erreur format hexa incorrect
*c = hexa[(unsigned char)c1] * 16 + hexa[(unsigned char)c2];
return DYN_OK;
}
WAPIDECL void dynCleanHexaMark(env * e, Dynamic * this)
{
if(this == NULL)
return;
/* */
/* equivalent a dynErase sur #xx, suppression "xx" et remplacement # par l'octet "xx" */
long i, pos = 0;
for(i = 0; i < this->mLg; i++)
{
if(this->mPtr[i] != '#' || i >= this->mLg - 2) // car si pas la place pour le code ascii, ne pas traiter # comme debut du code (securite)
{
if(pos != i) /* pour ne pas recopier les premiers caracteres quand pas de suppression */
this->mPtr[pos++] = this->mPtr[i];
else
pos++;
}
else
{
// remplace #xx (hexa) par l'octet correspondant
if(dynConvertCharHexaToChar(this->mPtr[i + 1], this->mPtr[i + 2], &this->mPtr[pos]) == DYN_ERR)
this->mPtr[pos] = '?'; // securite
pos++;
i += 2;
}
}
this->mLg = pos;
this->mPtr[this->mLg] = 0;
}
WAPIDECL long dynEscapeHexaMark(env * e, Dynamic * this)
{
/* remplace les sequences #xx par leur version echapee #23 #12 #34 */
/* ok en utf8 */
char c1, c2, c, * res;
long i;
for(i = 0; i < this->mLg; )
{
if(this->mPtr[i] == '#' && i < this->mLg - 2)
{
c1 = this->mPtr[i + 1];
c2 = this->mPtr[i + 2];
if(dynConvertCharHexaToChar(c1, c2, &c) == DYN_OK)
{
if(dynCtrl(e, this, this->mLg + 6, TRUE))
return DYN_ERR;
this->mPtr[i + 1] = '2';
this->mPtr[i + 2] = '3'; /* \x23 = # */
/* inserer 6 cars a (i + 3) */
/* deplacer la fin s'il y en a une */
if(this->mLg > i + 3)
memcopie(this->mPtr + i + 3 + 6, this->mPtr + i + 3, this->mLg - i - 3); // si lg a deplacer = 0, memcopie ne fait rien
this->mLg += 6;
this->mPtr[this->mLg] = 0;
/* */
res = dynConvertCharToCharHexa(c1);
this->mPtr[i + 3] = '#';
this->mPtr[i + 4] = res[0];
this->mPtr[i + 5] = res[1];
res = dynConvertCharToCharHexa(c2);
this->mPtr[i + 6] = '#';
this->mPtr[i + 7] = res[0];
this->mPtr[i + 8] = res[1];
/* */
i += 9;
}
else
return DYN_ERR;
}
else
i++;
}
return DYN_OK;
}
/* ********************************************** */
+13 -9
View File
@@ -23,10 +23,10 @@
#ifndef DYNAMIC_H
#define DYNAMIC_H
#define cFM '\xFE' /* 254 */
#define cFM '\xFE' /* 254 */
#define cVM '\xFD' /* 253 */
#define cSVM '\xFC' /* 252 */
#define cTM '\xFB' /* 251 */
#define cSVM '\xFC' /* 252 */
#define cTM '\xFB' /* 251 */
#define sFM "\xFE"
#define sVM "\xFD"
#define sSVM "\xFC"
@@ -47,7 +47,8 @@ enum {
DYN_SORT_ASC = 1,
DYN_SORT_DESC = 2,
DYN_NOTFOUND = -1 // quand pas trouve (index...)
DYN_NOTFOUND = -1, // quand index ne trouve pas
DYN_NOTLOCATED = 0 // locate ne trouve pas
};
/*typedef struct
@@ -84,6 +85,7 @@ WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg);
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 dynResize(env * e, Dynamic * this, long lgmax);
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);
@@ -139,16 +141,18 @@ 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 void dynTrimSpace(env * e, Dynamic * this);
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 void dynCut(env * e, Dynamic * this, long pos);
WAPIDECL long dynCleanString(env * e, Dynamic * this, octet debut, octet fin, long convHexa);
WAPIDECL char * dynConvertCharToCharHexa(octet c);
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c);
WAPIDECL void dynCleanHexaMark(env * e, Dynamic * this);
WAPIDECL long dynEscapeHexaMark(env * e, Dynamic * this);
/* ********************************************** */
#endif
+140
View File
@@ -0,0 +1,140 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "langage.h"
#include "dynamic.h"
// --- gestion protocole fastcgi
typedef struct {
long keepAlive;
long resteALireEntete;
long resteALireCorps;
char typeMessage; // BEGIN_REQUEST, etc.
long id; // id demande = id fastcgi
long lgCorps; // longueur corps du message (sans le padding)
long type; // type requete : OK ou ABORT
Dynamic param, dataIn, dataOut;
long error;
} modCtxFcgi;
enum {
FCGI_BEGIN_REQUEST = 1,
FCGI_ABORT_REQUEST = 2,
FCGI_END_REQUEST = 3,
FCGI_PARAMS = 4,
FCGI_STDIN = 5,
FCGI_STDOUT = 6,
/* role demande dans le BEGIN REQUEST */
FCGI_RESPONDER = 1,
FCGI_AUTHORIZER = 2,
FCGI_FILTER = 3,
/* code du "protocol status" lors du END REQUEST */
FCGI_REQUEST_COMPLETE = 0,
FCGI_CANT_MPX_CONN = 1,
FCGI_OVERLOADED = 2,
FCGI_UNKNOWN_ROLE = 3,
/* type requete en cours */
FCGI_REQUEST_OK = 0,
FCGI_REQUEST_ABORT = 1,
/* version prise en charge */
FCGI_VERSION = 1,
/* codes d'erreur */
FCGI_VERSION_UNSUPPORTED = 1,
FGCI_MESSAGETYPE_UNSUPPORTED = 2,
FGCI_PARAMETER_INCORRECT = 3,
/* codes retour */
FCGI_REQUEST_ERROR = -1,
FCGI_REQUEST_INPROGRESS = 0,
FCGI_REQUEST_AVAILABLE = 1
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WAPIDECL void Init(env * e, modCtxFcgi * ctx);
WAPIDECL void End(env * e, modCtxFcgi * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxFcgi * ctx, Dynamic * data);
WAPIDECL long MakeResponse(env * e, modCtxFcgi * ctx, long cr, Dynamic * reponse);
/*
exemples :
1. A simple request with no data on stdin, and a successful response:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2. Similar to example 1, but this time with data on stdin. The Web server chooses to send the parameters using more FCGI_PARAMS records than before:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3. Similar to example 1, but this time the application detects an error. The application logs a message to stderr, returns a page to the client, and returns non-zero exit status to the Web server. The application chooses to send the page using more FCGI_STDOUT records:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4. Two instances of example 1, multiplexed onto a single connection. The first request is more difficult than the second, so the application finishes the requests out of order:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
*/
+105 -330
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.
@@ -20,361 +20,136 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
enum {
/* types de requete FCGI */
FCGI_BEGIN_REQUEST = 1,
FCGI_ABORT_REQUEST = 2,
FCGI_END_REQUEST = 3,
FCGI_PARAMS = 4,
FCGI_STDIN = 5,
FCGI_STDOUT = 6,
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
/* demande dans le BEGIN REQUEST */
FCGI_RESPONDER = 1,
FCGI_AUTHORIZER = 2,
FCGI_FILTER = 3,
#include "langage.h"
#include "dynamic.h"
/* code du "protocl status" lors du END REQUEST */
FCGI_REQUEST_COMPLETE = 0,
FCGI_CANT_MPX_CONN = 1,
FCGI_OVERLOADED = 2,
FCGI_UNKNOWN_ROLE = 3,
#include "fcgi.h"
/* codes d'erreurs du module */
WFC_OK = 0, /* continuer a lire */
WFC_ERR = 1,
WFC_KEEPALIVE = 2,
WFC_REPONDRE = 3
};
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modCtxFcgi ctxFcgi;
} modEtat;
/* Descritpion du message en cours ; id = 0 si aucun en cours */
struct {
octet vers;
ent16 id;
octet keepAlive;
octet req; /* requete en cours : entete lue, attente message */
ent16 lg; /* longueur message apres entete a lire */
Dynamic param;
Dynamic dataIn;
Dynamic dataOut;
} fcgiReq;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
/* enchainement des appels a faire
- lecture : lire la socket et appeler readFcgi
si retour = ERR, sortir en erreur
si retour = OK, continuer a lire (mettre a la fin du message en cours) et appeler readFcgi
si retour = REPONDRE, envoyer la reponse
- calculer la reponse, lire les donnes avec getFcgiDataIn
- ecriture : appel writeFcgi pour formater la sortie et lire le resultat avec getFcgiDataOut
si retour = ERR, sortir en erreur
ecrire tout le message dans la socket, quand ok :
appel writeFcgi pour formater la suite (blocs de 65535 octets max) etc. Quand fini :
appel writeEndFcgi pour formater le message de fin et lire le resultat avec getFcgiDataOut
ecrire le message de fin sur la socket
si retour = OK, fermer la socket
si retour = KEEPALIVE, garder la socket ouverte pour la suite
- si sortie en erreur ou erreur socket, fermer la socket
*/
long getFcgiDataIn(env * e, Dynamic * msg)
static int setError(modEtat * p, int err)
{
if(fcgiReq.vers != 0 && fcgiReq.id != 0)
{
/* copie de param + dataIn dans msg : msg<1,x> = nom param, msg<2,x> = valeur param, msg<3> contenu requete */
dynSetLen(e, msg, 0);
dynConcat(e, msg, &fcgiReq.param);
dynStoreSz(e, msg, 3, "", 0);
dynConcat(e, msg, &fcgiReq.dataIn);
return WFC_OK;
}
else
return WFC_ERR; /* TODO pas de requete en cours */
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
long getFcgiDataOut(env * e, Dynamic * msg)
{
if(fcgiReq.vers != 0 && fcgiReq.id != 0)
{
/* copie de dataOut dans msg */
dynSetLen(e, msg, 0);
dynConcat(e, msg, &fcgiReq.dataOut);
return WFC_OK;
}
else
return WFC_ERR; /* TODO pas de requete en cours */
}
#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 readFcgi(env * e, Dynamic * msg)
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* "decodage" du message fcgi en entree */
if(msg->mLg < 8)
return WFC_RR; /* TODO longueur message incorrecte */
if(msg->ptr[0] != 1)
return WFC_ERR; /* TODO version message incorrecte (version 1 supportee uniquement) */
/* */
/* selon le type de message, controles */
if(fcgiReq.id != 0 && fcgiReq.vers != 0 && fcgi.req != 0)
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))
{
/* entete requete lue => prise en charge du message */
if(msg->mLg < fcgiReq->lg)
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
return WFC_OK; /* TODO message de la requete de longueur incorrecte : continuer a lire */
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
Init(e, &p_etat->ctxFcgi);
//
}
if(fcgiReq.req == FCGI_BEGIN_REQUEST)
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
End(e, &p_etat->ctxFcgi);
//
// 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
{
if(msg->ptr[0] == 0 && msg->ptr[1] == FCGI_RESPONDER)
{
/* ok, seul role pris en charge */
fcgiReq.keepAlive = msg->ptr[2];
fcgiReq.req = 0;
fcgiReq.lg = 0;
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
}
// 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
{
return WFC_ERR; /* TODO role non pris en charge */
}
}
if(fcgiReq.req == FCGI_PARAMS)
{
/* decoder le message pour maj fcgiReq.param <1,x> et <2,x> */
long pos = 0, lgnam, lgval, nb;
nb = dynDcount(e, &fcgiReq.param, 1, cFM, cVM);
for(; pos < fcgiReq->lg;)
{
if((lgnam = msg->ptr[pos]) > 127)
{
if(pos + 3 >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
lgnam = (lgnam & 127) << 24 + msg->ptr[pos + 1] << 16 + msg->ptr[pos + 2] << 8 + msg->ptr[pos + 3];
pos += 3;
}
if(++pos >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
if((lgval = msg->ptr[pos]) > 127)
{
if(pos + 3 >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
lgval = (lgval & 127) << 24 + msg->ptr[pos + 1] << 16 + msg->ptr[pos + 2] << 8 + msg->ptr[pos + 3];
pos += 3;
}
if(pos + lgnam + lgval >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
/* TODO copier name/valeur dans <param> ; utilise fcgiReq.dataOut comme var. temp */
dynCtrl(e, &fcgiReq.dataOut, lgnam + lgval + 2, FALSE);
nb++;
pos++;
memcopie(fcgiReq.dataOut.ptr, msg->ptr + pos, lgnam);
dynSetLen(e, &fcgiReq.dataOut, lgnam);
dynStore(e, &fcgiReq.dataOut, 1, nb, fcgiReq.dataOut, cFM, cVM);
pos += lgnam
memcopie(fcgiReq.dataOut.ptr, msg->ptr + pos, lgval);
dynSetLen(e, &fcgiReq.dataOut, lgval);
dynStore(e, &fcgiReq.dataOut, 2, nb, fcgiReq.dataOut, cFM, cVM);
pos += lgval;
}
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return OK;
}
if(fcgiReq.req == FCGI_STDIN)
{
dynConcatSz(e, &fcgiReq.dataIn, msg->mPtr, fcgiReq.lg);
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
if(msg->ptr[1] == FCGI_BEGIN_REQUEST)
else if(modFnIs(e, "error", 5))
{
if(fcgiReq.id != 0 || fcgiReq.vers != 0)
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
return WFC_ERR; /* TODO une autre requete deja en cours ; envoyer une requete END REQUEST avec prot.status FCGI_CANT_MPX_CONN (1) ? return OKCANTMPX */
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
fcgiReq.vers = msg->ptr[0];
fcgiReq.id = msg->ptr[2] << 8 + msg->ptr[3];
fcgiReq.req = FCGI_BEGIN_REQUEST;
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
dynSetLen(e, &fcgiReq.param, 0);
dynSetLen(e, &fcgiReq.dataIn, 0);
dynSetLen(e, &fcgiReq.dataOut, 0);
return WFC_OK;
}
else if(msg->ptr[1] == FCGI_PARAMS)
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
return WFC_ERR; /* TODO pas de requete en cours */
long cr = ExtractMessage(e, &p_etat->ctxFcgi, param1);
param2->num = cr * NUM_FACTEUR;
if(cr == FCGI_REQUEST_AVAILABLE)
dynSetAs(e, param3, &p_etat->ctxFcgi.dataIn);
}
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
if(fcgiReq.lg > 0)
fcgiReq.req = FCGI_PARAMS;
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
return WFC_OK;
}
else if(msg->ptr[1] == FCGI_STDIN)
{
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
{
return WFC_ERR; /* TODO pas de requete en cours */
}
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
if(fcgiReq.lg > 0)
fcgiReq.req = FCGI_STDIN;
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
return (fcgiReq.lg == 0 ? WFC_REPONDRE : WFC_OK); /* requete STDIN vide = fin de la demande : reponse a faire */
}
/* ----------------------------------------------------------------------------------------------- */
else
{
return WFC_ERR; /* TODO type requete non prise en charge */
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
long writeFcgi(env * e, Dynamic * msg)
{
/* codage du message fcgi pour envoi : se trouvera dans "fcgi.dataOut" */
if(fcgiReq.vers != 0 && fcgiReq.id != 0 && fcgiReq.req == 0 && fcgiReq.lg == 0) ; else
{
return WFC_ERR; /* etat de la requete ne permet pas d'envoyer */
}
/* envoyer par bloc de 65535 cars max, en multiple de 8 */
if(msg->mLg > 65535)
fcgiReq.lg = 65535;
else
fcgiReq.lg = msg->mLg;
dynCtrl(e, &fcgiReq.dataOut, fcgiReq.lg + 16, FALSE); /* TODO test si ok ; 16 pour s'eviter des calculs ici... */
fcgiReq.dataOut.ptr[0] = fcgiReq.vers;
fcgiReq.dataOut.ptr[1] = FCGI_STDOUT;
fcgiReq.dataOut.ptr[2] = fcgiReq.id >> 8;
fcgiReq.dataOut.ptr[3] = fcgiReq.id & 255;
fcgiReq.dataOut.ptr[4] = fcgiReq.lg >> 8;
fcgiReq.dataOut.ptr[5] = fcgiReq.lg & 255;
fcgiReq.dataOut.ptr[6] = (8 - (fcgiReq.lg % 8)) & 7;
fcgiReq.dataOut.ptr[7] = 0;
/* */
memcopie(fcgiReq.dataOut.mPtr + 8, msg->mPtr, fcgiReq.lg);
fcgiReq.dataOut.mLg = fcgireq.lg + 8 + fcgiReq.dataOut.ptr[6];
/* a supprimer du debut de msg */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
}
long writeEndFcgi(env * e)
{
/* codage du message fcgi pour envoi : se trouvera dans "fcgi.dataOut" */
if(fcgiReq.vers != 0 && fcgiReq.id != 0 && fcgiReq.req == 0 && fcgiReq.lg == 0) ; else
{
return WFC_ERR; /* etat de la requete ne permet pas d'envoyer */
}
/* */
fcgiReq.dataOut.ptr[0] = fcgiReq.vers;
fcgiReq.dataOut.ptr[1] = FCGI_END_REQUEST;
fcgiReq.dataOut.ptr[2] = fcgiReq.id >> 8;
fcgiReq.dataOut.ptr[3] = fcgiReq.id & 255;
fcgiReq.dataOut.ptr[4] = 0;
fcgiReq.dataOut.ptr[5] = 8;
fcgiReq.dataOut.ptr[6] = 0; /* padding multiple de 8 */
fcgiReq.dataOut.ptr[7] = 0;
/* */
fcgiReq.dataOut.ptr[8] = 0; /* statut applicatif */
fcgiReq.dataOut.ptr[9] = 0;
fcgiReq.dataOut.ptr[10] = 0;
fcgiReq.dataOut.ptr[11] = 0;
fcgiReq.dataOut.ptr[12] = 0; /* protocole status, 0 = OK, 1 = FCGI_CANT_MPX_CONN */
fcgiReq.dataOut.ptr[13] = 0;
fcgiReq.dataOut.ptr[14] = 0;
fcgiReq.dataOut.ptr[15] = 0;
/* */
fcgiReq.dataOut.mLg = 16;
return (fcgiReq.keepAlive ? WFC_KEEPALIVE : WFC_OK);
}
long writeCantMpxFcgi(env * e, octet vers, ent16 id)
{
/* */
fcgiReq.dataOut.ptr[0] = vers;
fcgiReq.dataOut.ptr[1] = FCGI_END_REQUEST;
fcgiReq.dataOut.ptr[2] = id >> 8;
fcgiReq.dataOut.ptr[3] = id & 255;
fcgiReq.dataOut.ptr[4] = 0;
fcgiReq.dataOut.ptr[5] = 8;
fcgiReq.dataOut.ptr[6] = 0; /* padding multiple de 8 */
fcgiReq.dataOut.ptr[7] = 0;
/* */
fcgiReq.dataOut.ptr[8] = 0; /* statut applicatif */
fcgiReq.dataOut.ptr[9] = 0;
fcgiReq.dataOut.ptr[10] = 0;
fcgiReq.dataOut.ptr[11] = 0;
fcgiReq.dataOut.ptr[12] = 1; /* protocole status, 0 = OK, 1 = FCGI_CANT_MPX_CONN */
fcgiReq.dataOut.ptr[13] = 0;
fcgiReq.dataOut.ptr[14] = 0;
fcgiReq.dataOut.ptr[15] = 0;
/* */
fcgiReq.dataOut.mLg = 16;
return WFC_OK;
}
/* pour appel depuis un serveur http ("client" genere des requetes pour l'application fastcgi)
ou gestion de l'application fastcgi (type module php) "serveur" avec requetes entrantes (accept)
et multiplexage ou non des requetes (sur ID ; autorisation ou non)
recupere un socket existant (comme sslMod)
*
* exemple de flux
* FCGI_BEGIN_REQUEST, 1,1, FCGI_RESPONDER/1, 0 ou 1 CGI_KEEP_CONN ("keep alive")
* FCGI_PARAMS, 1,4, "\0xB\0x2SERVER_PORT80\0xB\0xESERVER_ADDR199.170.183.42 ... "
* FCGI_PARAMS, 1,4, ""
* FCGI_STDIN, 1,5, "quantity=100&item=3047936"
* FCGI_STDIN, 1,5, "" ==> marque la fin de la question et attend de la reponse (au moins ce message apres BEGIN REQUEST)
*
* FCGI_STDOUT, 1,6, "Content-type: text/html\r\n\r\n<html>\n<head> ... "
* FCGI_STDOUT, 1,6, ""
* FCGI_END_REQUEST, 1,3, 0, FCGI_REQUEST_COMPLETE/0
*
* FastCGI
*---------
* chaque requete : entete 8 octets + contenu (multiple de 8)
* vers | type | MSB id LSB | MSB lg LSB |padlg | reser| requete
* +------+------+------+------+------+------+------+------+-----......------+
* 1 lg+padlg = multiple de 8
* type
* 1:BEGIN 3:END 4:PARAMS (paires Name/Value) 5:STDIN (brut) 6:STDOUT (brut)
*
* contenu requete pour chaque type
* 1: MSB role LSB |flags | reserve
* +------+------+------+------+------+------+------+------+ lg = 8
* role -> responder = 1 ; flags -> 0/1 : keep connection alive
* si keep alive = 1 avec fork, a la fin de la reponse, garder la socket ouverte
*
* 3: MSB . . status . . . LSB |pro st| reserve
* +------+------+------+------+------+------+------+------+ lg = 8
* pro st -> protocol status -> complete = 0
* status = statut applicatif (?)
*
* 4: lg nam|lg val| name | value |
* +------+------+--.....----+--...----+
* avec lg name et lg value < 127
* si > 127, encodage sur 4 octets MSB x x LSB ; lg maxi = 2^31-1 (bit 31 non significatif = 1)
*
* 5/6: contenu "libre"
*
*/
+388
View File
@@ -0,0 +1,388 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "fcgi.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
static long LireParametre(env * e, modCtxFcgi * ctx)
{
long pos = 0, len = ctx->dataOut.mLg;
octet * ptr = (octet *)ctx->dataOut.mPtr;
while(pos < len)
{
octet lgNom, lgVal;
long lgNomLong, lgValLong;
lgNom = ptr[pos++];
if(lgNom > 127)
{
if(pos + 3 > len)
return DYN_ERR; /* erreur */
lgNomLong = lgNom & 127;
lgNomLong = lgNomLong * 256 + ptr[pos++];
lgNomLong = lgNomLong * 256 + ptr[pos++];
lgNomLong = lgNomLong * 256 + ptr[pos++];
}
else
lgNomLong = lgNom;
//
if(pos >= len)
return DYN_ERR; /* erreur */
lgVal = ptr[pos++];
if(lgVal > 127)
{
if(pos + 3 > len)
return DYN_ERR; /* erreur */
lgValLong = lgVal & 127;
lgValLong = lgValLong * 256 + ptr[pos++];
lgValLong = lgValLong * 256 + ptr[pos++];
lgValLong = lgValLong * 256 + ptr[pos++];
}
else
lgValLong = lgVal;
//
if(pos + lgNomLong + lgValLong > len)
return DYN_ERR; /* erreur */
// lire les lgNomLong octets du nom du parametre et maj dans mParam<1,x>
// et lire les lgValLong octets de la valeur du parametre et maj dans mParam<2,x>
dynInsSz(e, &ctx->param, 1, 1, (char *)(ptr + pos), lgNomLong, cFM, cVM);
pos += lgNomLong;
dynInsSz(e, &ctx->param, 2, 1, (char *)(ptr + pos), lgValLong, cFM, cVM);
pos += lgValLong;
}
return OK;
}
static long EcrireEntete(env * e, modCtxFcgi * ctx, octet type, long id, long lg, long * lgpad)
{
if(dynCtrl(e, &ctx->dataOut, ctx->dataOut.mLg + 8, TRUE) != DYN_OK)
return DYN_ERR;
/* */
octet * ptr = (octet *)(ctx->dataOut.ptr + ctx->dataOut.mLg);
*lgpad = (8 - (lg % 8)) % 8;
dynSetLen(e, &ctx->dataOut, ctx->dataOut.mLg + 8);
/* */
*ptr++ = FCGI_VERSION;
*ptr++ = type;
*ptr++ = (id / 256) % 256; // MSB id
*ptr++ = id % 256; // LSB id
*ptr++ = (lg / 256) % 256; // MSB lg
*ptr++ = lg % 256; // LSB lg
*ptr++ = *lgpad;
*ptr = 0;
return OK;
}
static long EcrireCorps(env * e, modCtxFcgi * ctx, octet type, long crApplicatif, octet status)
{
switch(type)
{
case FCGI_END_REQUEST:
{
if(dynCtrl(e, &ctx->dataOut, ctx->dataOut.mLg + 8, TRUE) != DYN_OK)
return DYN_ERR;
//
octet * ptr = (octet *)(ctx->dataOut.ptr + ctx->dataOut.mLg);
dynSetLen(e, &ctx->dataOut, ctx->dataOut.mLg + 8);
//
*(ptr + 3) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 2) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 1) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 0) = crApplicatif % 256;
ptr += 4;
*ptr++ = status;
*ptr++ = 0;
*ptr++ = 0;
*ptr++ = 0;
break;
}
}
return OK;
}
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxFcgi * ctx)
{
ctx->keepAlive = 0;
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->typeMessage = 0; // BEGIN_REQUEST, etc.
ctx->id = 0; // id demande = id fastcgi
ctx->lgCorps = 0; // longueur corps du message
ctx->type = 0;
ctx->error = 0;
/* */
dynInit(e, &ctx->param, DYN_LGMIN);
dynInit(e, &ctx->dataIn, DYN_LGMIN);
dynInit(e, &ctx->dataOut, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxFcgi * ctx)
{
dynFree(e, &ctx->param);
dynFree(e, &ctx->dataIn);
dynFree(e, &ctx->dataOut);
}
WAPIDECL long ExtractMessage(env * e, modCtxFcgi * ctx, Dynamic * data)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
while(data->mLg > 0)
{
if(ctx->resteALireEntete == -1)
{
// entete fcgi attendue
if(data->mLg < 8)
return FCGI_REQUEST_INPROGRESS; /* attndre les donnees suivantes */
octet * ptr = (octet *)data->ptr;
octet vers = *ptr++;
ctx->typeMessage = *ptr++;
ctx->id = (*ptr++) * 256;
ctx->id += *ptr++;
long lg = (*ptr++) * 256;
lg += *ptr++;
long lgpad = *ptr;
dynCut(e, data, 8);
if(vers != FCGI_VERSION)
{
ctx->error = FCGI_VERSION_UNSUPPORTED;
return FCGI_REQUEST_ERROR; // erreur : version non prise en charge
}
//
ctx->resteALireEntete = 0;
ctx->lgCorps = lg;
ctx->resteALireCorps = lg + lgpad;
//
if(ctx->typeMessage == FCGI_BEGIN_REQUEST)
{
dynSetLen(e, &ctx->dataIn, 0);
dynSetLen(e, &ctx->param, 0);
}
if(ctx->typeMessage == FCGI_STDIN && ctx->resteALireCorps == 0)
{
// toutes les données de la requete ont ete recues : traiter puis envoyer reponse
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->type = FCGI_REQUEST_OK;
return FCGI_REQUEST_AVAILABLE;
}
if(ctx->typeMessage == FCGI_ABORT_REQUEST)
{
// forcer une reponse END_REQUEST
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->type = FCGI_REQUEST_ABORT;
return FCGI_REQUEST_AVAILABLE;
}
if(ctx->resteALireCorps == 0)
{
// message vide : attendre de nouveau l'entete
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
}
continue;
}
if(ctx->resteALireCorps > 0)
{
if(data->mLg < ctx->resteALireCorps)
return FCGI_REQUEST_INPROGRESS; // attendre : tout n'est pas recu
//
dynLet(e, &ctx->dataOut, data->mPtr, ctx->lgCorps); // ne pas prendre le padding...
dynCut(e, data, ctx->resteALireCorps);
ctx->resteALireCorps = 0;
ctx->resteALireEntete = -1;
//
switch(ctx->typeMessage)
{
case FCGI_BEGIN_REQUEST:
// verifier role = FCGI_RESPONDER ? si oui et erreur, forcer une reponse ABORT
ctx->keepAlive = (ctx->dataOut.mPtr[2] == 1);
// nota : durant les tests avec nginx, cela ne fonctionne pas : nginx ne reutilise pas la derniere socket ! Flag a remettre lors du EndRequest ?
break;
case FCGI_STDIN:
dynConcat(e, &ctx->dataIn, &ctx->dataOut);
break;
case FCGI_PARAMS:
// maj param sur attributs 1 & 2 en multi-valeurs (lu de dataOut)
if(LireParametre(e, ctx) != OK)
{
ctx->error = FGCI_PARAMETER_INCORRECT;
return FCGI_REQUEST_ERROR;
}
break;
default:
ctx->error = FGCI_MESSAGETYPE_UNSUPPORTED;
return FCGI_REQUEST_ERROR;
break;
}
}
}
return FCGI_REQUEST_INPROGRESS;
}
WAPIDECL long MakeResponse(env * e, modCtxFcgi * ctx, long cr, Dynamic * reponse)
{
long lgReponse = reponse->mLg, lgpad;
long debut = 0;
dynSetLen(e, &ctx->dataOut, 0);
/* */
if(ctx->type == FCGI_REQUEST_OK)
{
while (lgReponse > 0)
{
long lg;
if(lgReponse > 65535)
lg = 65535;
else
lg = lgReponse;
//
if(EcrireEntete(e, ctx, FCGI_STDOUT, ctx->id, lg, &lgpad) != OK)
return DYN_ERR;
dynConcatSz(e, &ctx->dataOut, reponse->mPtr + debut, lg);
if(lgpad > 0)
{
char pad[8] = "0000000";
pad[(lgpad) % 8] = 0;
dynConcatSz(e, &ctx->dataOut, pad, DYN_LGNONE);
}
//
lgReponse -= lg;
debut += lg;
}
// envoyer STDOUT de longueur nulle
if(EcrireEntete(e, ctx, FCGI_STDOUT, ctx->id, 0, &lgpad) != OK) // a envoyer si ABORT_REQUEST demande par le serveur Web ?
return DYN_ERR;
} // sinon forcement ABRT = que le END_REQUEST
// envoyer END_REQUEST
if(EcrireEntete(e, ctx, FCGI_END_REQUEST, ctx->id, 8, &lgpad) != OK)
return DYN_ERR;
if(EcrireCorps(e, ctx, FCGI_END_REQUEST, cr, FCGI_REQUEST_COMPLETE) != OK)
return DYN_ERR;
//
// reponse mis a jour au format fcgi
dynSetAs(e, reponse, &ctx->dataOut);
return OK;
}
/*
exemples :
1. A simple request with no data on stdin, and a successful response:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2. Similar to example 1, but this time with data on stdin. The Web server chooses to send the parameters using more FCGI_PARAMS records than before:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3. Similar to example 1, but this time the application detects an error. The application logs a message to stderr, returns a page to the client, and returns non-zero exit status to the Web server. The application chooses to send the page using more FCGI_STDOUT records:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4. Two instances of example 1, multiplexed onto a single connection. The first request is more difficult than the second, so the application finishes the requests out of order:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
---------
FastCGI
---------
chaque requete : entete 8 octets + contenu (multiple de 8)
vers | type | MSB id LSB | MSB lg LSB |padlg | reser| requete
+------+------+------+------+------+------+------+------+-----......------+
1 lg+padlg = multiple de 8
type
1:BEGIN 3:END 4:PARAMS (paires Name/Value) 5:STDIN (brut) 6:STDOUT (brut)
contenu requete pour chaque type
1: MSB role LSB |flags | reserve
+------+------+------+------+------+------+------+------+ lg = 8
role -> responder = 1 ; flags -> 0/1 : keep connection alive
si keep alive = 1 avec fork, a la fin de la reponse, garder la socket ouverte
3: MSB . . status . . . LSB |pro st| reserve
+------+------+------+------+------+------+------+------+ lg = 8
pro st -> protocol status -> complete = 0
status = statut applicatif (?)
4: lg nam|lg val| name | value |
+------+------+--.....----+--...----+
avec lg name et lg value < 127
si > 127, encodage sur 4 octets MSB x x LSB ; lg maxi = 2^31-1 (bit 31 non significatif = 1)
5/6: contenu "libre"
*/
+210 -114
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,6 +25,11 @@
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
@@ -32,24 +37,35 @@
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
#include "dynamic.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_RENAME = 1,
EXMOD_REMOVE = 2,
EXMOD_READ = 3,
EXMOD_WRITE = 4,
EXMOD_ACCESS = 5, /* open seek */
EXMOD_NB = 5
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Rename error",
"Delete error",
"Read error",
"Write error",
"Access error while opening/seeking" // 5
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -58,130 +74,198 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
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;
// les differentes fonctions : file.create/open/close/read/write/get/set/size/dir
// ( init/end/vers/error sont obligatoires pour tout module )
// create : creer un fichier ; flag overwrite = false : exception si existe, si flag = true, raz du fichier existant TODO
// open : ouvre un fichier existant, exception si inexistant TODO
// close : fermeture du fichier TODO
// read : lecture du fichier TODO
// write : ecriture du fichier TODO
// - - - - - - - - - - - - - - - - - - - -
// get : recupere dans param un dynamic contenant le fichier
// 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
/* 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 */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "create", 6))
else if(modFnIs(e, "rename", 6))
{
// todo...
// test
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
p_etat->error++;
printf("mod create %d\n", p_etat->error);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* utilisation de dynRead qui fait le travail, param1 : nom, param2 : contenu lu */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramOldPath = getParam(e, "oldPath", 7);
var * paramNewPath = getParam(e, "newPath", 7);
if(paramOldPath == NULL || paramNewPath == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramOldPath->type != VAR_DYNAMIC || paramNewPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynRead(e, param2, param1->mPtr) != DYN_OK)
exc = setError(p_etat, 1);
if(rename(paramOldPath->mPtr, paramNewPath->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
else if(modFnIs(e, "delete", 6))
{
/* copie du code de dynWrite, avec modif param1 : nom, param2 : contenu a ecrire */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
if(paramPath == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(remove(paramPath->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "append", 6))
{
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramContent = getParam(e, "content", 7);
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
else if(paramPath->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FILE * fic;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
if((fic = fopen(paramPath->mPtr, "ab")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "w")) == NULL)
if((fic = fopen(paramPath->mPtr, "a")) == NULL) /* mode "a" creer le fichier s'il n'existe pas (Unix et Windows) */
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
exc = setError(p_etat, EXMOD_ACCESS);
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 */
if(fseek(fic, 0, SEEK_END) != 0)
exc = setError(p_etat, EXMOD_ACCESS);
else if(fwrite(paramContent->mPtr, paramContent->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, EXMOD_WRITE);
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramContent = getParam(e, "content", 7);
/* utilisation de dynRead qui fait le travail */
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramContent->type != VAR_DYNAMIC)
var_let(e, paramContent, &e->int_dynamic, FALSE, FALSE);
if(dynRead(e, paramContent, paramPath->mPtr) != DYN_OK)
exc = setError(p_etat, EXMOD_READ);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramContent = getParam(e, "content", 7);
/* copie du code de dynWrite, avec modif param1 : nom, param2 : contenu a ecrire */
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
else if(paramPath->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FILE * fic;
#ifndef UNIX
if((fic = fopen(paramPath->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(paramPath->mPtr, "w")) == NULL)
#endif
exc = setError(p_etat, EXMOD_ACCESS); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fwrite(paramContent->mPtr, paramContent->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, EXMOD_WRITE); /* erreur generique : lire la vraie erreur ailleurs */
fclose(fic);
}
}
@@ -189,30 +273,34 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "size", 4))
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
/* */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramLength = getParam(e, "length", 6);
if(paramPath == NULL || paramLength == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
if((fic = fopen(paramPath->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "r")) == NULL)
if((fic = fopen(paramPath->mPtr, "r")) == NULL)
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
exc = setError(p_etat, EXMOD_ACCESS); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fseek(fic, 0, SEEK_END) != 0)
exc = setError(p_etat, 1); /* vraie erreur a mettre */
exc = setError(p_etat, EXMOD_ACCESS); /* vraie erreur a mettre */
else
{
if(paramLength->type != VAR_NUMBER)
var_let(e, paramLength, &e->int_number, FALSE, FALSE);
lg = ftell(fic); /* longueur du fichier */
param2->num = lg * NUM_FACTEUR;
paramLength->num = lg * NUM_FACTEUR;
}
fclose(fic);
}
@@ -221,28 +309,33 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "dir", 3))
{
/* copie du code de dynRead, plus court */
if(param1 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramFileList = getParam(e, "fileList", 8);
if(paramPath == NULL || paramFileList == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramFileList->type != VAR_DYNAMIC)
var_let(e, paramFileList, &e->int_dynamic, FALSE, FALSE);
/* copie du code de dynRead, plus court */
#ifdef UNIX
DIR * rep = NULL;
if((rep = opendir(param1->mPtr)) == NULL)
exc = setError(p_etat, 1); /* todo vraie erreur */
if((rep = opendir(paramPath->mPtr)) == NULL)
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
else
{
dynSetLen(e, param1, 0); // idem raz
dynSetLen(e, paramFileList, 0);
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(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, fic->d_name, DYN_LGNONE);
if(paramFileList->mLg > 0)
dynConcatSz(e, paramFileList, sFM, 1);
dynConcatSz(e, paramFileList, fic->d_name, DYN_LGNONE);
}
}
/* */
@@ -251,32 +344,35 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
dynConcatSz(e, param1, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(param1->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
dynLet(e, paramFileList, paramPath->mPtr, paramPath->mLg);
dynConcatSz(e, paramFileList, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(paramFileList->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
{
dynSetLen(e, param1, 0); // idem raz
dynSetLen(e, paramFileList, 0);
for(int cr = -1;cr != 0;)
{
if(strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
{
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, FindFileData.cFileName, DYN_LGNONE);
if(paramFileList->mLg > 0)
dynConcatSz(e, paramFileList, sFM, 1);
dynConcatSz(e, paramFileList, FindFileData.cFileName, DYN_LGNONE);
}
cr = FindNextFile(hFind, &FindFileData);
}
FindClose(hFind);
}
else
exc = setError(p_etat, 1); /* todo vraie erreur */
{
dynSetLen(e, paramFileList, 0);
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+125 -41
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,34 +27,23 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
#include "instr.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;
}
/*
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
neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60
search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70
gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80
endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90
numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100
modsep,101,other,102
*/
struct {
ent16 blank,comment,begin,background,library,end,except,throw,catch,include;
@@ -62,11 +51,12 @@ struct {
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,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;
ent16 indirect,typeof_,stringdq,stringq,ident,varsys,numberdec,numberint,minus,plus;
ent16 multiply,divide,divident,modulo,concat,listesep,identsep,modsep,other;
ent16 neg,round,sqrt,exp,type,len,count,dcount,field,index;
ent16 search,sortedsearch,change,format,insert,remove,tonum,tostring,equal,diff;
ent16 gt,lt,gte,lte,and,or,not,beginpar,endpar,beginh;
ent16 endh,begins,ends,indirect,typeof_,stringdq,stringq,ident,varsys,numberdec;
ent16 numberint,minus,plus,multiply,divide,divident,modulo,concat,listesep,identsep;
ent16 modsep,other;
} r;
void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
@@ -128,15 +118,18 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
/* */
r.neg = rg(e, regles, "neg", tmp);
r.round = rg(e, regles, "round", tmp);
r.sqrt = rg(e, regles, "sqrt", tmp);
r.exp = rg(e, regles, "exp", tmp);
r.type = rg(e, regles, "type", tmp);
r.len = rg(e, regles, "len", tmp);
r.count = rg(e, regles, "count", tmp);
r.dcount = rg(e, regles, "dcount", tmp);
r.field = rg(e, regles, "field", tmp);
r.index = rg(e, regles, "index", tmp);
r.search = rg(e, regles, "search", tmp);
r.change = rg(e, regles, "change", tmp);
/* */
r.search = rg(e, regles, "search", tmp);
r.sortedsearch = rg(e, regles, "sortedsearch", tmp);
r.change = rg(e, regles, "change", tmp);
r.format = rg(e, regles, "format", tmp);
r.insert = rg(e, regles, "insert", tmp);
r.remove = rg(e, regles, "remove", tmp);
@@ -144,10 +137,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.tostring = rg(e, regles, "tostring", tmp);
r.equal = rg(e, regles, "equal", tmp);
r.diff = rg(e, regles, "diff", tmp);
/* */
r.gt = rg(e, regles, "gt", tmp);
r.lt = rg(e, regles, "lt", tmp);
r.gte = rg(e, regles, "gte", tmp);
/* */
r.lte = rg(e, regles, "lte", tmp);
r.and = rg(e, regles, "and", tmp);
r.or = rg(e, regles, "or", tmp);
@@ -155,10 +148,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.beginpar = rg(e, regles, "beginpar", tmp);
r.endpar = rg(e, regles, "endpar", tmp);
r.beginh = rg(e, regles, "beginh", tmp);
/* */
r.endh = rg(e, regles, "endh", tmp);
r.begins = rg(e, regles, "begins", tmp);
r.ends = rg(e, regles, "ends", tmp);
/* */
r.indirect = rg(e, regles, "indirect", tmp);
r.typeof_ = rg(e, regles, "typeof", tmp);
r.stringdq = rg(e, regles, "stringdq", tmp);
@@ -166,10 +159,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.ident = rg(e, regles, "ident", tmp);
r.varsys = rg(e, regles, "varsys", tmp);
r.numberdec = rg(e, regles, "numberdec", tmp);
/* */
r.numberint = rg(e, regles, "numberint", tmp);
r.minus = rg(e, regles, "minus", tmp);
r.plus = rg(e, regles, "plus", tmp);
/* */
r.multiply = rg(e, regles, "multiply", tmp);
r.divide = rg(e, regles, "divide", tmp);
r.divident = rg(e, regles, "divident", tmp);
@@ -177,6 +170,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.concat = rg(e, regles, "concat", tmp);
r.listesep = rg(e, regles, "listesep", tmp);
r.identsep = rg(e, regles, "identsep", tmp);
/* */
r.modsep = rg(e, regles, "modsep", tmp);
r.other = rg(e, regles, "other", tmp);
}
@@ -188,17 +182,103 @@ enum {
static void formatage_asm(Dynamic * s, Dynamic * f)
{
// TODO
Dynamic trav, lig; /* variables de travail */
dynInit(&e, &trav, 0);
dynInit(&e, &lig, 0);
long sdlw = 0;
if(dynIndexSz(&e, s, "\r\n", 2, 1) > -1)
{
/* saut de ligne windows : supprimer \r et les remettre a la fin */
sdlw = 1;
/* supprimer les \r de la chaine ! */
dynErase(&e, s, "\r");
}
//
long numlig = 0, niveau = 0, flag_trt;
dynRemove(&e, s, NULL, 0, DYN_TRUE);
while(dynRemove(&e, s, &lig, 10, DYN_FALSE) > -1)
{
// traiter chaque ligne
numlig++;
if(lig.mLg == 0)
continue; // ligne vide
//
// mettre dans trav la ligne sans le debut (blanc/tab)
int i, pos = -1;
for(i = 0; i < lig.mLg; i++)
{
if(lig.mPtr[i] == 32 || lig.mPtr[i] == 9)
continue;
pos = i;
break;
}
if(pos == -1)
continue; /* ligne avec que des blancs/tabs : idem vide */
/* */
dynSubstr(&e, &lig, &trav, pos, lig.mLg - pos, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
/* recherche instr dans la liste */
int instr = -1, trouve = 0;
if(lig.mPtr[pos] == ';')
trouve = 1;
for(i = 0; i < 256 && !trouve; i++)
{
if(strncmp(libInstr + i * 4, trav.mPtr, 4) == 0)
{
// instruction <instr> trouvee
trouve = 1;
instr = i;
}
}
if(!trouve)
flag_trt = 0; // aligner sur le bloc courant, idem instruction ou commentaire
else if(instr == IN_PROG || instr == IN_LIBR || instr == IN_BACK || instr == IN_SUBR || instr == IN_PHDS || instr == IN_PIDS)
flag_trt = 1;
else if(instr == IN_ENDP || instr == IN_ENDS || instr == IN_ENDL)
flag_trt = 2;
else if(instr == IN_EXCE)
flag_trt = 3;
else
flag_trt = 0;
//
if(flag_trt == 1)
{
// niveau +1 apres
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + (niveau++) * TAB_COUNT);
}
else if(flag_trt == 2)
{
// niveau -1 avant
if(niveau > 0)
niveau--;
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + niveau * TAB_COUNT);
}
else if(flag_trt == 3)
{
// niveau -1 local sans changement
if(niveau > 0)
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + (niveau-1) * TAB_COUNT);
else
dynFmt(&e, &trav, &lig,'R', ' ', lig.mLg + niveau * TAB_COUNT);
}
else
{
// 0 : niveau courant
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + niveau * TAB_COUNT);
}
// changer la ligne courante avec sa version formatee
dynStoreSz(&e, f, numlig, DYN_NONE, lig.mPtr, lig.mLg, 10, DYN_NONE);
}
//
if(sdlw)
dynChange(&e, f, "\n", "\r\n", 0); /* remettre les sauts de ligne windows (0 = tous) */
//
dynFree(&e, &trav);
dynFree(&e, &lig);
}
static void formatage(Dynamic * s, Dynamic * f, int type)
static void formatage(Dynamic * s, Dynamic * f)
{
// s : source ; f : source apres formatage, type : 1 w, 2 pcode
if(type == 2)
{
formatage_asm(s, f);
return;
}
// s : source ; f : source apres formatage
//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 */
@@ -251,7 +331,7 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
if(valex.mLg == 0)
continue; // ligne vide
//
// contenu champ "n" : dynField(e, valex, tmp, 1, n, cFM, cVM, 1); dynIconv(e, tmp, encours, "X"); // en hexa
// contenu champ "n" : dynField(e, valex, tmp, 1, n, cFM, cVM, 1); hex2str(e, tmp, encours); // en hexa
// position source du champ "n" : dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
long nbval = dynDcount(&e, &valex, cVM, 2, cFM);
// MAJ var token pour fonctionner avec la macro nreg()
@@ -418,7 +498,7 @@ int main(int argc, char * argv[])
if(strcmp(argv[1], "-w") == 0)
type = 1;
else if(strcmp(argv[1], "-wa") == 0)
type = 2; // formatage du pcode (fichier .wa) TODO
type = 2; // formatage du pcode (fichier .wa)
else
{
printf("Usage: lwf [-w|-wa] <source>\n");
@@ -436,7 +516,11 @@ int main(int argc, char * argv[])
}
else
{
formatage(&source, &formate, type);
if(type == 2)
formatage_asm(&source, &formate);
else
formatage(&source, &formate);
/* */
printf("%s\n", formate.mPtr);
if(dynWrite(&e, &formate, argv[argfic]) != OK)
{
+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
+22 -219
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,221 +27,18 @@
#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
dynSetLen(&e, elem3, 0); // numero
dynField(&e, resultat, elem1, 1, DYN_NONE, 10, DYN_NONE, 1); // ligne 1 = token,numero,token,numero,...
dynField(&e, resultat, elem1, 1, 1, 10, ';', 1); // ligne 1 = token,numero,token,numero,...;etat;etat;etat
//long nb = dynDcount(e, elem1, ',', DYN_NONE, DYN_NONE) / 2;
long nb = 0;
dynSetLen(&e, resultat, 0);
dynLet(&e, resultat, "/* ", 3);
// Pass1 : commentaire
dynRemove(&e, elem1, NULL, 0, DYN_TRUE);
while(dynRemove(&e, elem1, elem2, ',', DYN_FALSE) > -1 && dynRemove(&e, elem1, elem3, ',', DYN_FALSE) > -1)
@@ -255,7 +52,7 @@ long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3
dynConcatSz(&e, resultat, ",", DYN_LGNONE);
dynConcatSz(&e, resultat, elem3->mPtr, DYN_LGNONE);
}
dynConcatSz(&e, resultat, "\n\n", 2);
dynConcatSz(&e, resultat, " */\n\n", 5);
// Pass2 struct
nb = 0;
dynRemove(&e, elem1, NULL, 0, DYN_TRUE);
@@ -313,10 +110,14 @@ long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3
return OK;
}
long gen_h(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3)
long gen_h(Dynamic * resultat, Dynamic * elem1)
{
dynErase(&e, resultat, "\r"); /* nettoyage au cas ou fichier Windows */
dynChange(&e, resultat, "\n", "\\n", DYN_ALL);
dynChange(&e, resultat, "\n", "\\n\"\n\"", DYN_ALL);
/* */
dynLet(&e, elem1, "static char file[] = \"", DYN_LGNONE);
dynSetSubstr(&e, resultat, elem1, 0, 0, 1, DYN_NONE, cFM, DYN_NONE);
dynConcatSz(&e, resultat, "\";", 2);
return OK;
}
@@ -350,13 +151,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);
@@ -364,23 +164,26 @@ 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, 0); /* 0 : runtime off, printf ok */
/* */
//dynConvert(&e, &valex, sFM sVM, "\n|");
//printf("valex %s\n", valex.mPtr);//
}
printf("Resultat (ret=%d):\n%s\n", ret, resultat.mPtr);
if(ret == OK)
ret = compile_maj_etat(&e, &resultat, &elem1, &elem2, &elem3);
/* */
printf("Compile a rediriger dans un fichier (ret=%d):\n\n%s\n\n", ret, resultat.mPtr);
//
if(ret == 0)
if(ret == OK)
{
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);
printf("Code C genere : \n\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);
ret = gen_h(&fichier, &elem1);
printf("Code H genere, a copier dans lex_files.h (idem compile) : \n\n%s\n\n", fichier.mPtr);
}
}
dynFree(&e, &valex);
+394 -101
View File
File diff suppressed because it is too large. Load diff
+19
View File
@@ -76,6 +76,25 @@ WAPIDECL char * copy_nom(env * e, const char * s)
return e->nom;
}
WAPIDECL char * raz_nom(env * e)
{
e->nom64[0] = 0;
e->nom64[1] = 0;
e->nom64[2] = 0;
return e->nom;
}
WAPIDECL int nom_is(env * e, const char * s)
{
long lg = strlen(s);
if(lg < 1 || lg > 24)
return FALSE;
ent64 f[3];
f[0] = 0; f[1] = 0; f[2] = 0;
strncpy((char *)f, s, lg);
return (e->nom64[0] == f[0] && e->nom64[1] == f[1] && e->nom64[2] == f[2]);
}
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
+2
View File
@@ -28,6 +28,8 @@
WAPIDECL void init_env(env * e);
WAPIDECL char * copy_nom(env * e, const char * s);
WAPIDECL char * raz_nom(env * e);
WAPIDECL int nom_is(env * e, const char * s);
WAPIDECL int modFnIs(env * e, const char * fn, int lg);
/* ************************************************************************** */
+34
View File
@@ -0,0 +1,34 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "langage.h"
#include "dynamic.h"
WAPIDECL void encodageMD2(env * e, var * entree, var * sortie);
WAPIDECL void encodageMD4(env * e, var * entree, var * sortie);
WAPIDECL void encodageMD5(env * e, var * entree, var * sortie);
WAPIDECL void encodageSha1(env * ctx, var * entree, var * sortie);
WAPIDECL void encodageAdler32(env * ctx, var * entree, var * sortie);
+137 -567
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,516 +25,33 @@
#include <time.h>
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#else
#include "windows.h" // TODO ici
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "hash.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
static void encodageMD2(env * e, var * entree, var * sortie)
{
unsigned char checksum[16] = {0};
unsigned char padding[16] = {0};
unsigned char buffer[48] = {0};
ent64 i, j, k;
static unsigned char tpi[]={ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115,
140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138,
23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121,
145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231,
191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207,
101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35,
221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244,
65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139,
227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248,
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->ptr);
unsigned char L = 0, T;
long longueur = entree->mLg;
while(longueur >= 16)
{
for(i = 0; i < 16; i++)
{
buffer[16 + i] = *p++;
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
longueur -= 16;
}
if(longueur > 0)
{
memcpy(padding, p, longueur);
}
ent64 nb = 16 - longueur;
memset(padding + longueur, nb, nb);
// calcul MD2 sur dernier bloc avec padding
for(i = 0; i < 16; i++)
{
buffer[16 + i] = padding[i];
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
// calcul MD2 sur checksum
for(i = 0; i < 16; i++)
{
buffer[16 + i] = checksum[i];
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
/* 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->ptr[j++] = carhex[buffer[i] / 16];
sortie->ptr[j++] = carhex[buffer[i] % 16];
}
dynSetLen(e, sortie, j); // len = 32 ici
}
static void majMD4(unsigned int * md4, pointeur buffer)
{
unsigned int A, B, C, D, tmp;
unsigned int buf[16];
unsigned char * octet;
ent64 i;
#define rot(T,s) (tmp = T, (tmp<<s) | (tmp>>(32-s)))
#define f(W,X,Y,Z,i,r) W = rot((W + ((X&Y) | ((~X)&Z)) + buf[i]),r)
#define g(W,X,Y,Z,i,r) W = rot(((W + ((X&Y) | (X&Z) | (Y&Z))) + buf[i] + 0x5A827999),r)
#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 = buffer;
for(i=0; i<16; i++, octet+=4)
buf[i] = (*octet) | ((*(octet+1))<<8) | ((*(octet+2))<<16) | ((*(octet+3))<<24);
/* */
/* printf("%08x %08x\n",buffer[0], buf[0]); */
A = md4[0];
B = md4[1];
C = md4[2];
D = md4[3];
/* Round 1 */
f(A , B , C , D , 0 , 3);
f(D , A , B , C , 1 , 7);
f(C , D , A , B , 2 , 11);
f(B , C , D , A , 3 , 19);
f(A , B , C , D , 4 , 3);
f(D , A , B , C , 5 , 7);
f(C , D , A , B , 6 , 11);
f(B , C , D , A , 7 , 19);
f(A , B , C , D , 8 , 3);
f(D , A , B , C , 9 , 7);
f(C , D , A , B , 10 , 11);
f(B , C , D , A , 11 , 19);
f(A , B , C , D , 12 , 3);
f(D , A , B , C , 13 , 7);
f(C , D , A , B , 14 , 11);
f(B , C , D , A , 15 , 19);
/* Round 2 */
g(A , B , C , D , 0 , 3);
g(D , A , B , C , 4 , 5);
g(C , D , A , B , 8 , 9);
g(B , C , D , A , 12 , 13);
g(A , B , C , D , 1 , 3);
g(D , A , B , C , 5 , 5);
g(C , D , A , B , 9 , 9);
g(B , C , D , A , 13 , 13);
g(A , B , C , D , 2 , 3);
g(D , A , B , C , 6 , 5);
g(C , D , A , B , 10 , 9);
g(B , C , D , A , 14 , 13);
g(A , B , C , D , 3 , 3);
g(D , A , B , C , 7 , 5);
g(C , D , A , B , 11 , 9);
g(B , C , D , A , 15 , 13);
/* Round 3 */
h(A , B , C , D , 0 , 3);
h(D , A , B , C , 8 , 9);
h(C , D , A , B , 4 , 11);
h(B , C , D , A , 12 , 15);
h(A , B , C , D , 2 , 3);
h(D , A , B , C , 10 , 9);
h(C , D , A , B , 6 , 11);
h(B , C , D , A , 14 , 15);
h(A , B , C , D , 1 , 3);
h(D , A , B , C , 9 , 9);
h(C , D , A , B , 5 , 11);
h(B , C , D , A , 13 , 15);
h(A , B , C , D , 3 , 3);
h(D , A , B , C , 11 , 9);
h(C , D , A , B , 7 , 11);
h(B , C , D , A , 15 , 15);
/* */
md4[0] += A;
md4[1] += B;
md4[2] += C;
md4[3] += D;
}
static void encodageMD4(env * e, var * entree, var * sortie)
{
unsigned char lg[8];
unsigned char buffer[64];
unsigned int md4[4]; // forcer sur 32 bits
ent64 i, j, k;
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
md4[0] = (unsigned int)0x67452301;
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, p);
p += 64;
longueur -= 64;
}
/* traitement du dernier bloc */
/* ajouter 0x80 et dans les 8 derniers octets le nombre de bits du flux initial (unsigned long long) */
/* si pas assez de place, faire un nouveau bloc */
memset(buffer, 0, 64);
if(longueur > 0)
memcpy(buffer, p, longueur);
buffer[longueur] = 128; /* 0x80 */
if(longueur <= 55)
{
/* un seul dernier bloc */
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(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, buffer);
}
else
{
/* 2 derniers blocs */
majMD4(md4, buffer);
/* */
memset(buffer, 0, 64);
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(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, buffer);
}
//
/* calcul md4 en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i=0, j=0, k=0; i<4; i++, j+=8, k+=4)
{
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j] = carhex[buffer[0]/16];
sortie->ptr[j+1] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
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->ptr[j+4] = carhex[buffer[0]/16];
sortie->ptr[j+5] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
sortie->ptr[j+6] = carhex[buffer[0]/16];
sortie->ptr[j+7] = carhex[buffer[0]%16];
}
dynSetLen(e, sortie, 32);
}
/* 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 ** );
@@ -544,131 +61,184 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// MD2(entree, resultat)
// MD4(entree, resultat)
//
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* 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 */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODETAT;
// renvoie la version du module/plugins
else if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1 == NULL)
exc = EX_MODETAT;
else if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "MD2", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD2(e, param1, param2);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD2(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD4", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD4(e, param1, param2);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD4(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD5", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD5(e, param1, param2);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD5(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "Sha1", 4))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageSha1(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "Adler32", 7))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageAdler32(e, paramPlaintext, paramHashedText);
}
}
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+717
View File
@@ -0,0 +1,717 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "hash.h"
#include "string.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ============ PRIVATE ===================================== */
static void majMD4(unsigned int * md4, pointeur buffer)
{
unsigned int A, B, C, D, tmp;
unsigned int buf[16];
unsigned char * octet;
ent64 i;
#define rot(T,s) (tmp = T, (tmp<<s) | (tmp>>(32-s)))
#define f(W,X,Y,Z,i,r) W = rot((W + ((X&Y) | ((~X)&Z)) + buf[i]),r)
#define g(W,X,Y,Z,i,r) W = rot(((W + ((X&Y) | (X&Z) | (Y&Z))) + buf[i] + 0x5A827999),r)
#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 = buffer;
for(i=0; i<16; i++, octet+=4)
buf[i] = (*octet) | ((*(octet+1))<<8) | ((*(octet+2))<<16) | ((*(octet+3))<<24);
/* */
/* printf("%08x %08x\n",buffer[0], buf[0]); */
A = md4[0];
B = md4[1];
C = md4[2];
D = md4[3];
/* Round 1 */
f(A , B , C , D , 0 , 3);
f(D , A , B , C , 1 , 7);
f(C , D , A , B , 2 , 11);
f(B , C , D , A , 3 , 19);
f(A , B , C , D , 4 , 3);
f(D , A , B , C , 5 , 7);
f(C , D , A , B , 6 , 11);
f(B , C , D , A , 7 , 19);
f(A , B , C , D , 8 , 3);
f(D , A , B , C , 9 , 7);
f(C , D , A , B , 10 , 11);
f(B , C , D , A , 11 , 19);
f(A , B , C , D , 12 , 3);
f(D , A , B , C , 13 , 7);
f(C , D , A , B , 14 , 11);
f(B , C , D , A , 15 , 19);
/* Round 2 */
g(A , B , C , D , 0 , 3);
g(D , A , B , C , 4 , 5);
g(C , D , A , B , 8 , 9);
g(B , C , D , A , 12 , 13);
g(A , B , C , D , 1 , 3);
g(D , A , B , C , 5 , 5);
g(C , D , A , B , 9 , 9);
g(B , C , D , A , 13 , 13);
g(A , B , C , D , 2 , 3);
g(D , A , B , C , 6 , 5);
g(C , D , A , B , 10 , 9);
g(B , C , D , A , 14 , 13);
g(A , B , C , D , 3 , 3);
g(D , A , B , C , 7 , 5);
g(C , D , A , B , 11 , 9);
g(B , C , D , A , 15 , 13);
/* Round 3 */
h(A , B , C , D , 0 , 3);
h(D , A , B , C , 8 , 9);
h(C , D , A , B , 4 , 11);
h(B , C , D , A , 12 , 15);
h(A , B , C , D , 2 , 3);
h(D , A , B , C , 10 , 9);
h(C , D , A , B , 6 , 11);
h(B , C , D , A , 14 , 15);
h(A , B , C , D , 1 , 3);
h(D , A , B , C , 9 , 9);
h(C , D , A , B , 5 , 11);
h(B , C , D , A , 13 , 15);
h(A , B , C , D , 3 , 3);
h(D , A , B , C , 11 , 9);
h(C , D , A , B , 7 , 11);
h(B , C , D , A , 15 , 15);
/* */
md4[0] += A;
md4[1] += B;
md4[2] += C;
md4[3] += D;
}
/* ============ PUBLIC ===================================== */
WAPIDECL void encodageMD2(env * e, var * entree, var * sortie)
{
unsigned char checksum[16] = {0};
unsigned char padding[16] = {0};
unsigned char buffer[48] = {0};
ent64 i, j, k;
static unsigned char tpi[]={ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115,
140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138,
23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121,
145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231,
191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207,
101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35,
221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244,
65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139,
227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248,
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->ptr);
unsigned char L = 0, T;
long longueur = entree->mLg;
while(longueur >= 16)
{
for(i = 0; i < 16; i++)
{
buffer[16 + i] = *p++;
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
longueur -= 16;
}
if(longueur > 0)
{
memcpy(padding, p, longueur);
}
ent64 nb = 16 - longueur;
memset(padding + longueur, nb, nb);
// calcul MD2 sur dernier bloc avec padding
for(i = 0; i < 16; i++)
{
buffer[16 + i] = padding[i];
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
// calcul MD2 sur checksum
for(i = 0; i < 16; i++)
{
buffer[16 + i] = checksum[i];
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
/* 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->ptr[j++] = carhex[buffer[i] / 16];
sortie->ptr[j++] = carhex[buffer[i] % 16];
}
dynSetLen(e, sortie, j); // len = 32 ici
}
WAPIDECL void encodageMD4(env * e, var * entree, var * sortie)
{
unsigned char lg[8];
unsigned char buffer[64];
unsigned int md4[4]; // forcer sur 32 bits
ent64 i, j, k;
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
md4[0] = (unsigned int)0x67452301;
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, p);
p += 64;
longueur -= 64;
}
/* traitement du dernier bloc */
/* ajouter 0x80 et dans les 8 derniers octets le nombre de bits du flux initial (unsigned long long) */
/* si pas assez de place, faire un nouveau bloc */
memset(buffer, 0, 64);
if(longueur > 0)
memcpy(buffer, p, longueur);
buffer[longueur] = 128; /* 0x80 */
if(longueur <= 55)
{
/* un seul dernier bloc */
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(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, buffer);
}
else
{
/* 2 derniers blocs */
majMD4(md4, buffer);
/* */
memset(buffer, 0, 64);
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(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, buffer);
}
//
/* calcul md4 en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i=0, j=0, k=0; i<4; i++, j+=8, k+=4)
{
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j] = carhex[buffer[0]/16];
sortie->ptr[j+1] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
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->ptr[j+4] = carhex[buffer[0]/16];
sortie->ptr[j+5] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
sortie->ptr[j+6] = carhex[buffer[0]/16];
sortie->ptr[j+7] = carhex[buffer[0]%16];
}
dynSetLen(e, sortie, 32);
}
/* MD5/SHA1 - 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 ROTATE_RIGHT(x, n) (((x) >> (n)) | ((x) << (32-(n))))
#define ROTATE_RIGHT_64(x, n) (((x) >> (n)) | ((x) << (64-(n))))
#define SHIFT_RIGHT(x, n) ((x) >> (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); }
#define CH(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define PARITY(x, y, z) ((x) ^ (y) ^ (z))
WAPIDECL 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) - little endian */
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);
}
WAPIDECL void encodageSha1(env * ctx, var * entree, var * sortie)
{
ent32 a, b, c, d, e, aNext, h0, h1, h2, h3, h4, t, w[80], k0, k1, k2, k3;
unsigned char buffer[64];
/* */
h0 = 0x67452301;
h1 = 0xefcdab89;
h2 = 0x98badcfe;
h3 = 0x10325476;
h4 = 0xc3d2e1f0;
/* */
k0 = 0x5a827999;
k1 = 0x6ed9eba1;
k2 = 0x8f1bbcdc;
k3 = 0xca62c1d6;
/* */
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) - big endian */
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[63] = (nb) & 0xff;
buffer[62] = (nb >> 8) & 0xff;
buffer[61] = (nb >> 16) & 0xff;
buffer[60] = (nb >> 24) & 0xff;
buffer[59] = (nb >> 32) & 0xff;
buffer[58] = (nb >> 40) & 0xff;
buffer[57] = (nb >> 48) & 0xff;
buffer[56] = (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[63] = (nb) & 0xff;
buffer[62] = (nb >> 8) & 0xff;
buffer[61] = (nb >> 16) & 0xff;
buffer[60] = (nb >> 24) & 0xff;
buffer[59] = (nb >> 32) & 0xff;
buffer[58] = (nb >> 40) & 0xff;
buffer[57] = (nb >> 48) & 0xff;
buffer[56] = (nb >> 56) & 0xff;
p = buffer;
}
/* */
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
/* */
/* deplier la boucle ? */
for (t = 0; t < 80; t++)
{
if(t < 16)
{
w[t] = (((ent32)(*p++)) << 24);
w[t] |= (((ent32)(*p++)) << 16);
w[t] |= (((ent32)(*p++)) << 8);
w[t] |= ((ent32)(*p++));
}
else
{
w[t] = w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16];
w[t] = ROTATE_LEFT(w[t], 1);
}
aNext = ROTATE_LEFT(a, 5) + e + w[t];
if(t < 20)
aNext += CH(b, c, d) + k0;
else if(t < 40)
aNext += PARITY(b, c, d) + k1;
else if(t < 60)
aNext += MAJ(b, c, d) + k2;
else
aNext += PARITY(b, c, d) + k3;
e = d;
d = c;
c = ROTATE_LEFT(b, 30);
b = a;
a = aNext;
}
/* */
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
p = sortie->ptr; /* 20 octets en hexa */
char hexa[16] = "0123456789abcdef";
/* */
*p++ = hexa[(h0 >> 28) & 0xf];
*p++ = hexa[(h0 >> 24) & 0xf];
*p++ = hexa[(h0 >> 20) & 0xf];
*p++ = hexa[(h0 >> 16) & 0xf];
*p++ = hexa[(h0 >> 12) & 0xf];
*p++ = hexa[(h0 >> 8) & 0xf];
*p++ = hexa[(h0 >> 4) & 0xf];
*p++ = hexa[(h0) & 0xf];
/* */
*p++ = hexa[(h1 >> 28) & 0xf];
*p++ = hexa[(h1 >> 24) & 0xf];
*p++ = hexa[(h1 >> 20) & 0xf];
*p++ = hexa[(h1 >> 16) & 0xf];
*p++ = hexa[(h1 >> 12) & 0xf];
*p++ = hexa[(h1 >> 8) & 0xf];
*p++ = hexa[(h1 >> 4) & 0xf];
*p++ = hexa[(h1) & 0xf];
/* */
*p++ = hexa[(h2 >> 28) & 0xf];
*p++ = hexa[(h2 >> 24) & 0xf];
*p++ = hexa[(h2 >> 20) & 0xf];
*p++ = hexa[(h2 >> 16) & 0xf];
*p++ = hexa[(h2 >> 12) & 0xf];
*p++ = hexa[(h2 >> 8) & 0xf];
*p++ = hexa[(h2 >> 4) & 0xf];
*p++ = hexa[(h2) & 0xf];
/* */
*p++ = hexa[(h3 >> 28) & 0xf];
*p++ = hexa[(h3 >> 24) & 0xf];
*p++ = hexa[(h3 >> 20) & 0xf];
*p++ = hexa[(h3 >> 16) & 0xf];
*p++ = hexa[(h3 >> 12) & 0xf];
*p++ = hexa[(h3 >> 8) & 0xf];
*p++ = hexa[(h3 >> 4) & 0xf];
*p++ = hexa[(h3) & 0xf];
/* */
*p++ = hexa[(h4 >> 28) & 0xf];
*p++ = hexa[(h4 >> 24) & 0xf];
*p++ = hexa[(h4 >> 20) & 0xf];
*p++ = hexa[(h4 >> 16) & 0xf];
*p++ = hexa[(h4 >> 12) & 0xf];
*p++ = hexa[(h4 >> 8) & 0xf];
*p++ = hexa[(h4 >> 4) & 0xf];
*p++ = hexa[(h4) & 0xf];
/* */
dynSetLen(ctx, sortie, 40);
/* */
a = b = c = d = e = h0 = h1 = h2 = h3 = h4 = 0;
memset(buffer, 0, 64);
}
WAPIDECL void encodageAdler32(env * ctx, var * entree, var * sortie)
{
ent32 s1 = 1, s2 = 0, mod = 65521;
unsigned char * p = entree->ptr;
long lg = entree->mLg;
for(long i = 0; i < lg; i++, p++)
s2 = (s2 + (s1 = ((s1 + *p) % mod))) % mod; /* TODO tester perfs avec modulo fait tous les 5802 octets */
s2 = (s2 << 16) | s1;
/* */
p = sortie->ptr; /* 4 octets en hexa */
char hexa[16] = "0123456789abcdef";
*p++ = hexa[(s2 >> 28) & 0xf];
*p++ = hexa[(s2 >> 24) & 0xf];
*p++ = hexa[(s2 >> 20) & 0xf];
*p++ = hexa[(s2 >> 16) & 0xf];
*p++ = hexa[(s2 >> 12) & 0xf];
*p++ = hexa[(s2 >> 8) & 0xf];
*p++ = hexa[(s2 >> 4) & 0xf];
*p++ = hexa[(s2) & 0xf];
dynSetLen(ctx, sortie, 8);
}
+229 -10
View File
@@ -39,13 +39,52 @@
#endif
// =============== PRIVATE ========================================================================
static ent64 fmix64(ent64 h)
{
h ^= h >> 33;
h *= 0xff51afd7ed558ccdull;
h ^= h >> 33;
h *= 0xc4ceb9fe1a85ec53ull;
h ^= h >> 33;
return h;
}
static entry * calc_entry(char * val, var * varht)
{
/* fonctionne avec des noms de 24 octets max (val) */
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 h = 0x9e3779b97f4a7c15ull;
hash = h;
hash ^= *p++;
hash *= h;
hash ^= *p++;
hash *= h;
hash ^= *p;
hash *= h;
/* SplitMix64 */
hash ^= hash >> 30;
hash *= 0xbf58476d1ce4e5b9ull;
hash ^= hash >> 27;
hash *= 0x94d049bb133111ebull;
hash ^= hash >> 31;
}
/* */
if(0)
{
ent64 * p = (ent64 *)val;
ent64 h = 0x9e3779b97f4a7c15ull;
hash = h;
hash ^= fmix64((*p++) + h);
hash ^= fmix64((*p++) + 0x517cc1b727220a95ull);
hash ^= fmix64((*p) + 0x6eed0e9da4d94a4full);
// si longueur connue : mettre en plus la ligne suivante
//hash ^= fmix64(len * 0x9e3779b97f4a7c15ull);
hash = fmix64(hash);
}
/* */
if(0) {
ent64 * p = (ent64 *)val;
ent64 k = *p++;
@@ -70,12 +109,12 @@ static entry * calc_entry(char * val, var * varht)
hash ^= k;
hash *= m;
}
/* */
/* algo de D. B e r n s t e i n / M u r m u r h a s h 6 4 */
if(1) {
hash = 5381;
for(int iCle = 0; iCle < 24; iCle++)
if(val[iCle])
hash = hash + (hash<<5) + val[iCle]; /* hash*33 */
hash = hash + (hash << 5) + val[iCle]; /* hash * 33 */
else
break; // stop au premier \0
}
@@ -98,7 +137,13 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
if(varht == NULL || v == NULL || nom == NULL)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
{
if((varht = (var *)varht->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
/* chaque groupe : | nom1 ... 0 (24) | var1 (40) | nom2 ... 0 (24) | var2 (40) | */
@@ -129,17 +174,19 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
pentry->nom2 = 0;
pentry->nom3 = 0;
pentry->content.type = 0;
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return;
}
if(action == HASH_WRITE) /* write */
{
/* ecraser la var presente (et liberer), sauf si meme var : NON car si type different => KO !! et d'ailleurs, est-ce utile ici puisque même pointeur ?? */
/* ecraser la var presente (et liberer), sauf si meme var : NON car si type different => KO !! et d'ailleurs, est-ce utile ici puisque meme pointeur ?? */
if(*v != (var *)&pentry->content)
{
/* liberer pentry->content ; si PARAM, libere la var pointee + copie de la var */
var_let(e, &pentry->content, *v, TRUE, FALSE); /* verifier que TRUE et FALSE sont ok ici !!! */
}
((entry *)varht->ptr)->pvar = &pentry->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
}
return;
}
@@ -159,7 +206,7 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
{
*v = NULL;
/* renvoyer la premiere entree libre trouvee, l'entree PAS la var (si NULL, il faudra rappeler do) */
((entry *)varht->ptr)->pvar = pfree == NULL ? NULL : &pfree->content;
((entry *)varht->ptr)->pvar = (var *)pfree;
}
/* si action = 2 delete et pas trouve : RAS */
if(action == HASH_WRITE) /* write */
@@ -182,10 +229,51 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
pfree->content.type = VAR_NULL;
var_let(e, &pfree->content, *v, FALSE, FALSE); /* copie de la var */
((entry *)varht->ptr)->pvar = &pfree->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
//printf("hashwrite non trouve %s %p -> %p (ad e->int_dynamic %p)\n", nom, *v, &pfree->content, &e->int_dynamic);
}
}
WAPIDECL void hashtable_deleteentry(env * e, var * varht, var * content)
{
/* cf. hashtable_do / DELETE */
/* liberer la variable "pentry->content" ; si PARAM, libere la var pointee */
var_free(e, content, TRUE);
entry * pentry = (entry *)((pointeur)content - 3 * sizeof(ent64));
pentry->nom1 = 0;
pentry->nom2 = 0;
pentry->nom3 = 0;
pentry->content.type = 0;
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
}
WAPIDECL var * hashtable_writeinfirstfreeentry(env * e, var * varht, char * nom, var * v)
{
if(varht == NULL || v == NULL || nom == NULL)
return NULL;
if(varht->type == VAR_PARAM)
if((varht = (var *)varht->ptr) == NULL) /* travailler avec la var pointee ! */
return NULL;
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return NULL;
/* */
entry * pfree = (entry *)(((entry *)varht->ptr)->pvar);
if(pfree == NULL)
{
/* securite : faire HASH_WRITE */
hashtable_do(e, HASH_WRITE, varht, copy_nom(e, nom), &v);
return ((entry *)varht->ptr)->pvar; /* last item written */
}
/* */
pfree->nom1 = *(ent64 *)nom;
pfree->nom2 = *((ent64 *)nom + 1);
pfree->nom3 = *((ent64 *)nom + 2);
var_let(e, &pfree->content, v, FALSE, FALSE); /* copie de la var */
((entry *)varht->ptr)->pvar = &pfree->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return &pfree->content;
}
WAPIDECL var * hashtable_lastitemwritten(var * varht)
{
return ((entry *)varht->ptr)->pvar;
@@ -211,6 +299,7 @@ WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v)
{
var * pvar;
entry * pentry;
if(((entry *)varht->ptr)->content.ptr == NULL) return FALSE; /* write/delete sur la hash durant le select : arret ! */
/* ne fait pas une copie de la variable en retour, mais renvoie un pointeur dans la hash !! */
for(pvar = &((entry *)varht->ptr)->content; pvar->type < varht->modulo; pvar->type++)
{
@@ -281,8 +370,8 @@ WAPIDECL void hashtable_clear(env * e, var * varht)
hashtable_free_ovf(e, varht);
/* raz contenu */
memset(varht->ptr, 0, varht->modulo * varht->separateur);
/* raz ptr par securite */
hashtable_select(e, varht);
/* raz ptr par securite (utile ??) */
//hashtable_select(e, varht);
}
WAPIDECL long hashtable_count(env *e, var * varht)
@@ -294,10 +383,67 @@ WAPIDECL long hashtable_count(env *e, var * varht)
while(hashtable_next(e, varht, e->nom, &pvar))
nb++;
/* raz ptr par securite */
hashtable_select(e, varht);
//hashtable_select(e, varht);
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return nb;
}
WAPIDECL void hashtable_serialize(env * e, var * varht, var * out)
{
/* >>> format (ignorer sub/null/buffer/param), point d'entree = hash
N:nom\n
number\n
D:lg:nom\n
dynamic\n (lg ne tient pas compte du \n)
+:nom\n
<contenu hash/objet>
-:\n (fin hash)
S:nom()\n (que le nom de la sub)
*/
if(varht == NULL || out == NULL) return;
if((varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT) || out->type != VAR_DYNAMIC) return;
/* */
var * v;
hashtable_select(e, varht);
while(hashtable_next(e, varht, raz_nom(e), &v))
{
if(v->type == VAR_NUMBER)
{
dynConcatSz(e, out, "N:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
dynConcatSz(e, out, NumberToSz(e, v->num, NULL, NULL), DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
}
else if (v->type == VAR_DYNAMIC)
{
dynConcatSz(e, out, "D:", 2);
dynConcatSz(e, out, Int64ToSz(e, v->mLg, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, out, ":", 1);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
dynConcat(e, out, v);
dynConcatSz(e, out, "\n", 1);
}
else if (v->type == VAR_SUBROUTINE)
{
dynConcatSz(e, out, "S:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "()\n", 3);
}
else if(v->type == VAR_HASHTABLE || v->type == VAR_OBJECT)
{
dynConcatSz(e, out, "+:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
/* */
hashtable_serialize(e, v, out);
/* */
dynConcatSz(e, out, "-:\n", 3);
}
}
}
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
{
entry * pentry; /* pointe sur une entree */
@@ -311,6 +457,8 @@ WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
if(varht == NULL)
return;
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
if(e->demon)
@@ -380,4 +528,75 @@ WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
printf("taille totale=%lld, occupee=%lld (taux %lld%%), nb item=%lld\n", tot, occ, occ * 100 / tot, nb);
}
WAPIDECL void hashtable_analyze(env * e, var * varht)
{
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 */
/* affiche le contenu d'une hashtable */
if(varht == NULL)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
if(varht == NULL)
return;
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
if(e->demon)
{
dynPrintfInt64(e, "hashtable analyze modulo=" PRINTF_MARK " separateur=", varht->modulo, 0);
dynPrintfInt64(e, PRINTF_MARK "\n", varht->separateur, 0);
}
else
printf("hashtable analyze modulo=%lld separateur=%lld\n", varht->modulo, varht->separateur);
/* */
ent64 nb_entry, occ_entry, nb_item_group, nb_group_1entry = 0, nb_empty_group = 0, nb_item = 0;
ent64 occ_entry_min = varht->separateur/sizeof(entry), occ_entry_max = 0;
ent64 nb_entry_min = (ent64)(-1), nb_entry_max = 0;
ent64 nb_item_group_min = (ent64)(-1), nb_item_group_max = 0;
/* */
pchain = (entry *)varht->ptr;
for(groupe = 0; groupe < varht->modulo; groupe++)
{
nb_entry = 0;
nb_item_group = 0;
pchain_first = pchain;
do
{
nb_entry++;
occ_entry = 0;
pentry = pchain + 1; /* la premiere est toujours "occupee", utilisee en interne par la hashtable : ne pas mettre dans les stats */
while((ent64)pentry - (ent64)pchain < varht->separateur)
{
if((pentry->nom1 | pentry->nom2 | pentry->nom3 | pentry->content.type) == 0)
; /* entree libre */
else
{
occ_entry++; /* entree occupee */
nb_item_group++;
nb_item++;
}
pentry++;
}
/* */
if(occ_entry < occ_entry_min) occ_entry_min = occ_entry;
if(occ_entry > occ_entry_max) occ_entry_max = occ_entry;
/* chainage */
} while ((pchain = (entry *)pchain->chainage_avant) != 0);
pchain = (entry *)((ent64)pchain_first + varht->separateur);
/* */
if(nb_entry < nb_entry_min) nb_entry_min = nb_entry;
if(nb_entry > nb_entry_max) nb_entry_max = nb_entry;
if(nb_item_group < nb_item_group_min) nb_item_group_min = nb_item_group;
if(nb_item_group > nb_item_group_max) nb_item_group_max = nb_item_group;
if(nb_item_group == 0) nb_empty_group++;
if(nb_entry == 1) nb_group_1entry++;
}
printf(" => nb bloc/group: min=%lld, max=%lld, 1bloc=%lld/%lld\n", nb_entry_min, nb_entry_max, nb_group_1entry, varht->modulo);
printf(" => occ bloc: min=%lld, max=%lld (/%lld)\n", occ_entry_min, occ_entry_max, varht->separateur/sizeof(entry) - 1);
printf(" => nb item/group: min=%lld, max=%lld, empty=%lld/%lld\n", nb_item_group_min, nb_item_group_max, nb_empty_group, varht->modulo);
printf(" => nb item total=%lld\n", nb_item);
}
/* ********************************************** */
+5
View File
@@ -32,8 +32,13 @@ 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 var * hashtable_writeinfirstfreeentry(env * e, var * varht, char * nom, var * v);
WAPIDECL void hashtable_deleteentry(env * e, var * varht, var * content);
WAPIDECL void hashtable_serialize(env * e, var * varht, var * out);
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail);
WAPIDECL void hashtable_analyze(env * e, var * varht);
/* ********************************************** */
#endif
+68
View File
@@ -0,0 +1,68 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "langage.h"
#include "dynamic.h"
// --- gestion protocole http
typedef struct {
int state; /* etat de decodage des trames http : 0 entete a lire, 1 en cours lecture entete, 2 lecture corps, 3 lecture corps mode chunk */
ent64s lengthToRead; /* longueur de donnees (corps) restant a lire */
ent64s chunkLength;
Dynamic header; /* liste des entetes http <1,x> nom entete (minuscule) <2, x> valeur, le decodage de la premiere ligne est mis ici : http_method http_path http_vers */
Dynamic content; /* corps du message http */
Dynamic line, tmp; /* buffer de lecture d'une ligne, variable de travail */
Dynamic methodList; /* liste des methodes http supportees */
int error;
} modCtxHttp;
enum {
/* state */
HTTPSTATE_HEADERTOREAD = 0,
HTTPSTATE_READINGHEADER = 1,
HTTPSTATE_READINGCONTENT = 2,
HTTPSTATE_READINGCHUNKEDCONTENT = 3,
/* codes d'erreur */
HTTP_METHOD_KO = 1,
HTTP_METHOD_GET_MISSING = 2,
HTTP_INCORRECT_LENGTH = 3,
HTTP_COLON_MISSING = 4,
HTTP_CHUNK_BODY_CRLF_MISSING = 5,
HTTP_STATUS_KO = 6,
/* code retour */
HTTP_REQUEST_ERROR = -1,
HTTP_REQUEST_INPROGRESS = 0,
HTTP_REQUEST_COMPLETE = 1,
HTTP_REQUEST_EXPECTCONTINUE = 2
};
WAPIDECL void InitHttp(env * e, modCtxHttp * ctx);
WAPIDECL void FreeHttp(env * e, modCtxHttp * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data, int isRequest);
WAPIDECL long MakeExpect100(env * e, modCtxHttp * ctx, Dynamic * reponse);
WAPIDECL long MakeResponse(env * e, modCtxHttp * ctx, long cr, Dynamic * reponse);
+229
View File
@@ -0,0 +1,229 @@
/* **********************************************
__ __ __
\ \/ \/ / 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"
/* ============================================================================================= */
#include "http.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modCtxHttp ctxHttp;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_HTTP_ERROR = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Protocol error"
};
/* ============================================================================================= */
#include "mod.c"
#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 */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
InitHttp(e, &p_etat->ctxHttp);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
FreeHttp(e, &p_etat->ctxHttp);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "getRequest", 10))
{
/* get param in the right order */
var * paramInput = getParam(e, "inputData", 9);
var * paramContent = getParam(e, "content", 7);
var * paramReturn = getParam(e, "returnCode", 10);
if(paramInput == NULL || paramContent == NULL || paramReturn == NULL)
exc = EX_MODPARAM;
else if(paramInput->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramReturn->type != VAR_NUMBER)
var_let(e, paramReturn, &e->int_number, FALSE, FALSE);
/* */
long cr = ExtractMessage(e, &p_etat->ctxHttp, paramInput, TRUE);
/* */
if(cr == HTTP_REQUEST_COMPLETE)
dynConcat(e, paramContent, &p_etat->ctxHttp.content);
else if(cr == HTTP_REQUEST_ERROR)
p_etat->error = p_etat->ctxHttp.error; /* A REVOIR !! */
/* */
paramReturn->num = cr * NUM_FACTEUR;
}
}
/* --------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getResponse", 11))
{
/* get param in the right order */
var * paramInput = getParam(e, "inputData", 9);
var * paramContent = getParam(e, "content", 7);
var * paramReturn = getParam(e, "returnCode", 10);
if(paramInput == NULL || paramContent == NULL || paramReturn == NULL)
exc = EX_MODPARAM;
else if(paramInput->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramReturn->type != VAR_NUMBER)
var_let(e, paramReturn, &e->int_number, FALSE, FALSE);
/* */
long cr = ExtractMessage(e, &p_etat->ctxHttp, paramInput, FALSE);
/* */
if(cr == HTTP_REQUEST_COMPLETE)
dynSetAs(e, paramContent, &p_etat->ctxHttp.content);
else if(cr == HTTP_REQUEST_ERROR)
p_etat->error = p_etat->ctxHttp.error; /* A REVOIR !! */
/* */
paramReturn->num = cr * NUM_FACTEUR;
}
}
/* --------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getHeader", 9))
{
/* get param in the right order */
var * paramHeader = getParam(e, "headerList", 10);
if(paramHeader == NULL)
exc = EX_MODPARAM;
else
{
if(paramHeader->type != VAR_DYNAMIC)
var_let(e, paramHeader, &e->int_dynamic, FALSE, FALSE);
/* */
dynSetAs(e, paramHeader, &p_etat->ctxHttp.header);
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+365
View File
@@ -0,0 +1,365 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "http.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
#define CRLF "\r\n"
#define LEN_CRLF 2
/* ***** PUBLIC *************** */
WAPIDECL void InitHttp(env * e, modCtxHttp * ctx)
{
ctx->error = 0;
ctx->state = HTTPSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
dynInit(e, &ctx->header, DYN_LGMIN);
dynInit(e, &ctx->content, DYN_LGMIN);
dynInit(e, &ctx->line, DYN_LGMIN);
dynInit(e, &ctx->tmp, DYN_LGMIN);
dynInit(e, &ctx->methodList, DYN_LGMIN);
dynLet(e, &ctx->methodList, "GET" sFM "HEAD" sFM "POST" sFM "OPTIONS" sFM "CONNECT" sFM "TRACE" sFM "PUT" sFM "PATCH" sFM "DELETE", DYN_LGNONE); // laisser GET en premier sinon KO
}
WAPIDECL void FreeHttp(env * e, modCtxHttp * ctx)
{
dynFree(e, &ctx->header);
dynFree(e, &ctx->content);
dynFree(e, &ctx->line);
dynFree(e, &ctx->tmp);
dynFree(e, &ctx->methodList);
}
WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data, int isRequest)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
/* isRequest est TRUE pour decoder une requete http, FALSE pour decoder une reponse http */
if(ctx->state == HTTPSTATE_HEADERTOREAD || ctx->state == HTTPSTATE_READINGHEADER)
{
for(;;)
{
long ind = dynIndexSz(e, data, CRLF, LEN_CRLF, 1);
if(ind < 0)
return HTTP_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
dynSetLen(e, &ctx->line, 0);
if(ind > 0)
dynSubstr(e, data, &ctx->line, 0, ind, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, ind + LEN_CRLF);
/* ici <ctx->line> contient la ligne d'entete et <data> est a jour avec les donnees suivantes */
/* */
if(ctx->state == HTTPSTATE_HEADERTOREAD)
{
/* premiere ligne du protocole : principale difference selon le type : Request-line or Status-line */
if(isRequest)
{
long posMethod;
dynField(e, &ctx->line, &ctx->tmp, 1, DYN_NONE, ' ', DYN_NONE, 1); // method
if((posMethod = dynLocateSz(e, &ctx->methodList, ctx->tmp.mPtr, cFM, DYN_NONE, DYN_NONE)) == DYN_NOTLOCATED)
{
ctx->error = HTTP_METHOD_KO;
return HTTP_REQUEST_ERROR;
}
dynSetLen(e, &ctx->header, 0); // vider le header
dynInsSz(e, &ctx->header, 1, 1, "http_method", 11, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 2, DYN_NONE, ' ', DYN_NONE, 1); // path
dynInsSz(e, &ctx->header, 1, 1, "http_path", 9, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 3, DYN_NONE, ' ', DYN_NONE, 1);
if(ctx->tmp.mLg == 0)
{
/* quand http version absent : version http 0.9 implicite, GET seul autorise, pas d'entete et pas de ligne vide => corps (https://fr.wikipedia.org/wiki/Hypertext_Transfer_Protocol) */
if(posMethod != 1)
{
ctx->error = HTTP_METHOD_GET_MISSING; /* http 0.9 GET seul autorise */
return HTTP_REQUEST_ERROR;
}
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynInsSz(e, &ctx->header, 2, 1, "HTTP/0.9", 8, cFM, cVM);
dynSetLen(e, &ctx->content, 0);
return HTTP_REQUEST_COMPLETE; /* requete terminee */
}
else
{
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
}
/* */
ctx->state = HTTPSTATE_READINGHEADER;
ctx->lengthToRead = 0;
}
else
{
/* response */
dynField(e, &ctx->line, &ctx->tmp, 1, DYN_NONE, ' ', DYN_NONE, 1); // http/version
dynSetLen(e, &ctx->header, 0); // vider le header
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
/* */
dynField(e, &ctx->line, &ctx->tmp, 2, DYN_NONE, ' ', DYN_NONE, 1); // code statut
ent64s status = dynSzToNum(e, ctx->tmp.mPtr, DYN_FALSE, 3, (long *)&ctx->tmp.mInternal);
if(status < 100 || status > 599 || ctx->tmp.mLg != 3)
{
ctx->error = HTTP_STATUS_KO;
return HTTP_REQUEST_ERROR;
}
dynInsSz(e, &ctx->header, 1, 1, "http_status", 11, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
/* */
dynField(e, &ctx->line, &ctx->tmp, 3, DYN_NONE, ' ', DYN_NONE, 1); // description
/* */
ctx->state = HTTPSTATE_READINGHEADER;
ctx->lengthToRead = 0;
}
}
else
{
/* entetes a lire */
if(ctx->line.mLg == 0)
{
// fin des entetes
dynSetLen(e, &ctx->content, 0);
long posExpect = dynLocateSz(e, &ctx->header, "expect", cVM, 1, cFM);
if(posExpect != DYN_NOTLOCATED)
{
dynField(e, &ctx->header, &ctx->tmp, 2, posExpect, cFM, cVM, 1);
if(dynCompare(e, &ctx->tmp, CMP_EQ, "100-continue", 12))
{
/* envoyer une reponse 100 expect-continue avant de lire le corps */
ctx->state = HTTPSTATE_READINGCONTENT;
return HTTP_REQUEST_EXPECTCONTINUE;
}
}
if(dynLocateSz(e, &ctx->header, "http_chunked", cVM, 1, cFM) == DYN_NOTLOCATED)
{
if(ctx->lengthToRead == 0)
{
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_COMPLETE; /* pas de contenu ici */
}
ctx->state = HTTPSTATE_READINGCONTENT;
}
else
{
ctx->lengthToRead = 0;
ctx->chunkLength = -1; // indique que la longueur a lire est a prendre dans le contenu, car mode chunked
ctx->state = HTTPSTATE_READINGCHUNKEDCONTENT;
}
break;
}
else
{
/* lecture de l'entete */
dynBegin(e, &ctx->line);
if(dynNext(e, &ctx->line, &ctx->tmp, ':') > -1)
{
dynCut(e, &ctx->line, ctx->line.mInternal + 1);
// nom entete en minuscule
dynErase(e, &ctx->tmp, " ");
str2lower(e, &ctx->tmp);
if(dynLocateSz(e, &ctx->header, ctx->tmp.mPtr, cVM, 1, cFM) != DYN_NOTLOCATED)
continue; // entete deja memorisee, ignorer le doublon
// valeur
dynTrimSpace(e, &ctx->line);
// tmp = nom entete, line = valeur entete
dynIns(e, &ctx->header, 1, 1, &ctx->tmp, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->line, cFM, cVM);
// mode chunk ?
if(dynCompare(e, &ctx->tmp, CMP_EQ, "transfer-encoding", 17) && dynCompare(e, &ctx->line, CMP_EQ, "chunked", 7))
{
dynInsSz(e, &ctx->header, 1, 1, "http_chunked", 12, cFM, cVM);
dynInsSz(e, &ctx->header, 2, 1, "1", 1, cFM, cVM);
}
if(dynCompare(e, &ctx->tmp, CMP_EQ, "content-length", 14))
{
ctx->lengthToRead = dynToNum(e, &ctx->line, DYN_FALSE, 0); /* longueur negative cause une erreur */
if(ctx->line.mInternal == DYN_ERR)
{
ctx->error = HTTP_INCORRECT_LENGTH; // erreur de conversion du content-length : ingorer et on continue
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_ERROR;
}
}
}
else
{
/* erreur de syntaxe dans l'entete */
ctx->error = HTTP_COLON_MISSING;
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_ERROR;
}
}
}
} /* endless for */
}
/* */
if(ctx->state == HTTPSTATE_READINGCONTENT)
{
// lecture corps, ctx->lengthToRead est > 0 ici
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return HTTP_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues */
dynConcatSz(e, &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
ctx->state = HTTPSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
return HTTP_REQUEST_COMPLETE;
}
}
/* */
if(ctx->state == HTTPSTATE_READINGCHUNKEDCONTENT)
{
// chunkLength : -1 longueur chunk a lire, > 0 chunk a lire ou en cours de lecture (+ CRLF de fin : dans lengthToRead)
for(;;)
{
if(ctx->chunkLength < 0)
{
long ind = dynIndexSz(e, data, CRLF, LEN_CRLF, 1);
if(ind < 0)
return HTTP_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
dynSetLen(e, &ctx->line, 0);
if(ind > 0)
dynSubstr(e, data, &ctx->line, 0, ind, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, ind + LEN_CRLF);
/* ici <ctx->line> contient la ligne de longueur du chunk */
/* longueur du chunk en hexa */
ctx->chunkLength = hex2num(e, &ctx->line); // quid erreur de conversion ?
ctx->lengthToRead = ctx->chunkLength + 2; // integre le CRLF de fin de chunk
}
if(ctx->chunkLength >= 0)
{
if(data->mLg == 0)
return HTTP_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
/* */
/* donnees du chunk */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return HTTP_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues, controle CRLF de fin du chunk */
dynConcatSz(e, &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
if(strncmp(ctx->content.mPtr + ctx->content.mLg - LEN_CRLF, CRLF, LEN_CRLF) == 0)
{
dynSetLen(e, &ctx->content, ctx->content.mLg - LEN_CRLF);
if(ctx->chunkLength == 0)
{
/* dernier chunk (vide) recu : message complet */
ctx->state = HTTPSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
return HTTP_REQUEST_COMPLETE;
}
else
{
/* fin du chunk, attente du suivant */
ctx->chunkLength = -1;
}
}
else
{
/* erreur de formatage du chunk : le corps ne se termine pas par CRLF */
ctx->error = HTTP_CHUNK_BODY_CRLF_MISSING;
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_ERROR;
}
}
}
} /* endless for */
}
/* */
return HTTP_REQUEST_ERROR;
}
WAPIDECL long MakeExpect100(env * e, modCtxHttp * ctx, Dynamic * reponse)
{
dynLet(e, reponse, "HTTP/1.1 100 Continue" CRLF CRLF, DYN_LGNONE);
return OK;
}
WAPIDECL long MakeResponse(env * e, modCtxHttp * ctx, long cr, Dynamic * reponse)
{
// en versoin 0.9, pas d'entete => directement le contenu !
//if((pos = dynLocateSz(e, &ctx->header, "http_version", cVM, 1, cFM)) == DYN_NOTLOCATED)
// else
// dynField(e, &ctx->header, &ctx->tmp, 2, pos, cFM, cVM, 1);
// si tmp == "HTTP/0.9" : contenu direct
//
//header.SetAs("HTTP/1.1 ");
//if(cr == '0' || cr == '1' || cr == '2')
// header.AppendString("200 OK"); // controles ont ete faits
//else if(cr == 'R') // URI ou corps de la requête incorrect
// header.AppendString("400 Bad Request");
//else if(cr == 'S')
// header.AppendString("500 Internal Server Error");
//else if(cr == 'S')
// header.AppendString("501 Not Implemented");
//else
// header.AppendString("500 Internal Server Error"); // erreur par defaut
////
//if(mKeepAlive)
// header.AppendString("\r\nConnection: keep-alive");
//else
// header.AppendString("\r\nConnection: close");
////
//header.AppendString("\r\nContent-Type: ");
//if(contentType == 'j')
// header.AppendString("application/json");
//else
// header.AppendString("application/octet-stream\r\nContent-Length: "); // valeur par defaut 'generique', ne doit pas arriver
//header.AppendString(reponse.GetContentSize());
//header.AppendString("\r\n\r");
////
//reponse.SetDelimiter(cLF);
//reponse.InsertField(1, header);
return OK;
}
+2 -1
View File
@@ -66,7 +66,8 @@ void instr_unassemble(env * e, pointeur debutBin, ent64 nolig)
case IN_PNAM:
case IN_CLIB:
case IN_PVAI:
case IN_CPSH:
case IN_CPAN:
case IN_CPHN:
case IN_PHDE:
case IN_PIDE:
case IN_PHDH:
+22 -12
View File
@@ -41,14 +41,14 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"INTE" "FRAC" "NEGN" "ABSN" "MODL" "PSHC" "PSHV" "POPV" "PVAR" "PVAH"
"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"
"PSH4" "PSH5" "PSH6" "PSH7" "PSH8" "PSH9" "PSHA" "SQRT" "IEXP" "CLIB" /* 50-59 */
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPAN" "RETT"
"SELE" "RNXT" "CPHA" "PHDE" "PIDE" "PHDH" "PIDH" "PHDO" "PIDO" "PHDS"
"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" "SDBG" "PHDN" "PIDN" "SADV" "VLET" /* 110-119 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" /* 124 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "SSRC" "SSCS" "CPHH" "CPHN" "xxxx" /* 128 */
"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"
@@ -61,7 +61,7 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"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" /* 200-249 */
"xxxx" "LIBR" "ENDL" "TEST" "ENDS" "ENDP"};
"PROG" "LIBR" "ENDL" "BACK" "ENDS" "ENDP"};
char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "FOR"};
@@ -184,10 +184,10 @@ char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "F
#define IN_PSH9 55
#define IS_PSHA "\x38"
#define IN_PSHA 56
#define IS_PROG "\x39"
#define IN_PROG 57
#define IS_BACK "\x3A"
#define IN_BACK 58
#define IS_SQRT "\x39"
#define IN_SQRT 57
#define IS_IEXP "\x3A"
#define IN_IEXP 58
#define IS_CLIB "\x3B"
#define IN_CLIB 59
@@ -207,8 +207,8 @@ char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "F
#define IN_PSHT 66
#define IS_CRAZ "\x43"
#define IN_CRAZ 67
#define IS_CPSH "\x44"
#define IN_CPSH 68
#define IS_CPAN "\x44"
#define IN_CPAN 68
#define IS_RETT "\x45"
#define IN_RETT 69
@@ -326,13 +326,23 @@ char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "F
#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_CPHH "\x7F"
#define IN_CPHH 127
#define IS_CPHN "\x80"
#define IN_CPHN 128
#define IS_PROG "\xFA"
#define IN_PROG 250
#define IS_LIBR "\xFB"
#define IN_LIBR 251
#define IS_ENDL "\xFC"
#define IN_ENDL 252
#define IS_TEST "\xFD"
#define IN_TEST 253
#define IS_BACK "\xFD"
#define IN_BACK 253
#define IS_ENDS "\xFE"
#define IN_ENDS 254
#define IS_ENDP "\xFF"
+18 -18
View File
@@ -52,21 +52,21 @@ typedef struct
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
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
EXMODJSON_DECODE_INCORRECT_CHAR = 1,
EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED = 2,
EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED = 3,
EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED = 4,
EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER = 5,
EXMODJSON_MEM = 6,
EXMODJSON_DECODE_UNTERMINATED_STRING = 7,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT = 8,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY = 9,
EXMODJSON_DECODE_UNEXPECTED_KEY = 10,
EXMODJSON_DECODE_UNEXPECTED_VALUE = 11,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT = 12,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT = 13,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY = 14,
EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON = 15
};
/*
@@ -76,9 +76,9 @@ enum {
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);
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * json, var * cle, var * valeur);
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * cle, var * valeur, var * printable);
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * content, var * done);
/*
+125 -72
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,21 +27,47 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "json.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextJson jsonCtx;
} modEtat;
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
/* codes erreur dans dans json.h */
EXMOD_NB = 15
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Unexpected character",
"True keywoed expected",
"False keyword expected",
"Null keyword expected",
"Unpexted character while decoding number", // 5
"Memory error",
"End of string expected",
"Unexpected start object character",
"Unexpected start array character",
"Unexpected key", // 10
"Unexpected value",
"Unexpected next character",
"Unexpected end object character",
"Unexpected end array character",
"Unexpected end of json" // 15
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -50,127 +76,154 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
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
// - - - - - - - - - - - - - - - - - - - -
/* 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 */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == 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
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "decode", 6))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramJsonText = getParam(e, "jsonText", 8);
var * paramExtractedKey = getParam(e, "extractedKey", 12);
var * paramExtractedValue = getParam(e, "extractedValue", 14);
if(paramJsonText == NULL || paramExtractedKey == NULL || paramExtractedValue == NULL)
exc = EX_MODPARAM;
else if(paramJsonText->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* param2 and param3 are dynamic (output) ; param1 must be a dynamic (input) */
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // bad type of parameter 1 or 2 or 3
else
// param3 = 1 for no double-quoted json (key and string value, except if <space> is present in value) ; future use
exc = setError(p_etat, jsonDecode(e, &p_etat->jsonCtx, param1, param2, param3));
if(paramExtractedKey->type != VAR_DYNAMIC)
var_let(e, paramExtractedKey, &e->int_dynamic, FALSE, FALSE);
if(paramExtractedValue->type != VAR_DYNAMIC)
var_let(e, paramExtractedValue, &e->int_dynamic, FALSE, FALSE);
exc = setError(p_etat, jsonDecode(e, &p_etat->jsonCtx, paramJsonText, paramExtractedKey, paramExtractedValue));
}
}
/* ============================================================================================= */
else if(modFnIs(e, "print", 5))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramExtractedKey = getParam(e, "extractedKey", 12);
var * paramExtractedValue = getParam(e, "extractedValue", 14);
var * paramPrettyPrint = getParam(e, "prettyPrint", 11);
if(paramExtractedKey == NULL || paramExtractedValue == NULL || paramPrettyPrint == NULL)
exc = EX_MODPARAM;
else if(paramExtractedKey->type != VAR_DYNAMIC || paramExtractedValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* param2 and param3 are dynamic (output) ; param1 must be a dynamic (input) */
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // bad type of parameter 1 or 2 or 3
else
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, param1, param2, param3));
if(paramPrettyPrint->type != VAR_DYNAMIC)
var_let(e, paramPrettyPrint, &e->int_dynamic, FALSE, FALSE);
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, paramExtractedKey, paramExtractedValue, paramPrettyPrint));
}
}
else if(modFnIs(e, "treeFetch", 9))
{
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramFetchParameters = getParam(e, "fetchParameters", 15);
var * paramDone = getParam(e, "done", 4);
if(paramFetchParameters == NULL || paramDone == NULL)
exc = EX_MODPARAM;
else if(paramFetchParameters->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
/* param1 must be a hash table (input) */
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));
if(paramDone->type != VAR_NUMBER)
var_let(e, paramDone, &e->int_number, FALSE, FALSE);
exc = setError(p_etat, jsonTreeFetch(e, &p_etat->jsonCtx, paramFetchParameters, paramDone));
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+38 -38
View File
@@ -682,76 +682,76 @@ WAPIDECL int jsonEnd(env * e, modContextJson * ctx)
return OK;
}
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * json, var * cle, var * valeur)
{
return Decode(e, ctx, param1->mPtr, param2, param3);
return Decode(e, ctx, json->mPtr, cle, valeur);
}
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * cle, var * valeur, var * printable)
{
char value[4] = " : \0", path = '/', index = '@';
//
return MakePrintable(e, ctx, param1, param2, param3, path, index, value);
return MakePrintable(e, ctx, printable, cle, valeur, path, index, value);
}
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * content, var * done)
{
// KeyList, CurrentKey, Name, Value, DecodeCle, DecodeValue; // Dynamic
// 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);
hashtable_do(e, HASH_READ, content, copy_nom(e, "DecodedKey"), &tree.DecodeCle);
hashtable_do(e, HASH_READ, content, copy_nom(e, "DecodedValue"), &tree.DecodeValue);
if(tree.DecodeCle == NULL || tree.DecodeValue == NULL)
{
param2->num = NUM_UN;
done->num = NUM_UN;
return OK; // TODO erreur
}
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, content, 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);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyList"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "CurrentKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Name"), &v);
hashtable_do(e, HASH_WRITE, content, 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);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyField"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyItem"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Id"), &v);
v->num = 0;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Parent"), &v);
hashtable_do(e, HASH_WRITE, content, 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);
hashtable_do(e, HASH_WRITE, content, 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_WRITE, content, copy_nom(e, "ItemCount"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "IdKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "ParentKey"), &v);
hashtable_do(e, HASH_WRITE, content, 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, content, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, content, copy_nom(e, "CurrentKey"), &tree.CurrentKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Name"), &tree.Name);
hashtable_do(e, HASH_READ, content, 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_do(e, HASH_READ, content, copy_nom(e, "KeyField"), &tree.KeyField);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyItem"), &tree.KeyItem);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyCount"), &tree.KeyCount);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ItemCount"), &tree.ItemCount);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Id"), &tree.Id);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Parent"), &tree.Parent);
hashtable_do(e, HASH_READ, content, copy_nom(e, "IdKey"), &tree.IdKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ParentKey"), &tree.ParentKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ValuePresent"), &tree.ValuePresent);
/* */
//hashtable_printdebug(e, param1, 1);
//hashtable_printdebug(e, content, 1);
if(GetNextTreeFetch(e, &tree)) // TRUE = pas fini
param2->num = NUM_ZERO; // var <fin>
done->num = NUM_ZERO; // var <fin>
else
param2->num = NUM_UN;
done->num = NUM_UN;
return OK;
}
+1281 -585
View File
File diff suppressed because it is too large. Load diff
+48 -24
View File
@@ -48,14 +48,9 @@ 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
#define ENT64_MAX 999999999999999999ull /* 18 chiffres dont 5 decimales version non signee pour calcul */
#define NUM_PI 314159ll
#define NUM_MOINSUN -100000ll
#define NUM_ZERO 0ll
@@ -69,6 +64,7 @@ typedef __int128 ent128s; // temporaire pour les calculs intermediaires
#define NUM_HUIT 800000ll
#define NUM_NEUF 900000ll
#define NUM_FACTEUR 100000ll /* facteur multiplicatif/diviseur pour virgule fixe (5 decimales ici) */
#define FACTEUR 100000 /* constante int 32 bits */
#define NUM_ENTIER 13 /* nb chiffres partie entiere maxi */
#define NUM_DECIMAL 5 /* nb de decimales maxi, mais precision max = NUM_DECIMAL - 1 (4 decimales ici) */
@@ -87,16 +83,17 @@ enum {
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 */
VAR_EMPTY = 0, /* retour @empty fonction type(expr) */
VAR_UNDECLARED = -1,
VAR_UNDECLARED = 0, /* cas de retour si pas de var dans "typeof var1.var2.var3" */
WCP_ASCII = 0, /* pour valeur par defaut */
WCP_WIN1252 = 1252,
WCP_8859_1 = 28591,
WCP_8859_15 = 28605,
WCP_UTF8 = 65001,
WCP_DEFAULT = WCP_WIN1252 // UTF8 ??
WCP_DEFAULT = WCP_ASCII // WIN1252 ? UTF8 ?
};
typedef struct {
@@ -133,7 +130,7 @@ typedef struct {
ent64 write; /* buffer */
ent64 misc; /* hashtable/objet et subroutine (si_except) */
ent64s mInternal; /* pour dynamic */
pointeur etat; /* pour module, etat utilise d'appels en appels */
pointeur etat; /* pour module (SUB), etat utilise d'appels en appels ; pour VAR_PARAM indique si variable est un element de hash (PVAH) */
};
} var; /* 40 octets */
@@ -152,7 +149,7 @@ typedef struct {
};
union {
ent64 nom3;
var * pvar; /* sert a renvoyer l'adresse de la var suite a WRITE */
var * pvar; /* sert a renvoyer l'adresse de la var suite a WRITE / adresse de la premiere entry libre si READ non trouve */
};
var content;
} entry; /* 64 octets = 24 + var(40) */
@@ -213,10 +210,10 @@ enum {
//
enum {
OK = 0,
EX_DIV0 = 1, /* exceptions */
EX_DIV0 = 1, /* division par zero */
EX_MEM = 2, /* memalloc ko */
EX_BUFOVF = 3, /* depassement de capacite du buffer */
EX_IO = 4,/* erreur d'entree/sortie (leture fichier...) */
EX_IO = 4, /* erreur d'entree/sortie (lecture 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 */
@@ -253,12 +250,18 @@ enum {
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 */
EXNB = 40 /* MEMO !!!! */
EX_SORTEDSEARCH_KO = 41, /* erreur de parametre (type de tri incorrect) */
EX_SQRT_NEG = 42, /* racine carre d'un nombre negatif non calculee */
EX_INT_EXP = 43, /* exponentiation fractionnaire non calculee */
EX_VARPARAM_KO = 44, /* la variable passee en parametre n'est plus presente en memoire */
EX_PARAM_NOTFOUND = 45, /* la variable passee en parametre est affectee a un nom de parametre inconnu de la sub */
EX_NUMOVF = 46, /* depassement de capacite lors d'un calcul */
EX_INPUT_TTY = 47, /* terminal indisponible, lecture entree standard impossible */
EXNB = 47 /* MEMO !!!! */
};
typedef struct {
typedef struct env {
/* environnement global */
var num_stack; /* buffers qui contiennent les 2 piles : nombre et appel */
var call_stack; /* mettre les adresses des params dans la call_stack => au debut de la fn, tout est depile ! */
var numstr_stack; /* pile contenant number et string */
var g; /* hashtable qui contient toutes les variables "globales" (begin/end) + objets + vars systemes + modules */
@@ -269,8 +272,6 @@ 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 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 */
@@ -280,8 +281,9 @@ typedef struct {
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 */
var * ad_var_class; /* donne l'adresse de la var dynamic _class de l'objet ad_var_obj */
var * ad_var_sav; /* pour memoriser ad_var sur une affectation simple let a.b = c.d, instruction SADV / VLET / PHDV / PIDV / CPHH / CPHN */
var * ad_var_dele; /* memorise ad_var pour DELE */
/* */
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 ! */
@@ -325,24 +327,29 @@ typedef struct {
pointeur si_except; /* position dans le source du code traitant les exceptions (apres instruction EXC) */
/* */
pointeur binaddr; /* permet de lire les adresses binaires en mode Trace */
/* */
pointeur ctxLzw; /* pointeur sur le contexte lzw pour decompresser les binaires wp compresse */
/* */
ent64 mem_numb; /* nombre de blocs memoire alloues */
ent64 mem_size; /* taille des bloc memoire alloues */
/* */
ent64 oid_cpt; /* compteur pour les object ID (OID) */
/* */
char oidc[24]; /* conversion en ascii, mis en binaire (16 chiffres max car 2x8 octets), oid3 ne sert pas (0)
seuls les 15 premiers cars servent, les 8 derniers sont des fillers pour aller a 24 cars */
char oidc[24]; /* conversion en ascii, mis en binaire (16 chiffres max car 2x8 octets), oid3 ne sert pas (0)
seuls les 15 premiers cars servent, les 8 derniers sont des fillers pour aller a 24 cars */
/* */
union { /* var interne pour copie d'une cle d'acces a un element d'une hashtable */
ent64 nom64[3];
char nom[24];
};
int zero1; /* permet de gerer la chaine precedente nom en sz */
union {
ent64 fn64[3];
char fn[24]; // nom de la fonction appelee par un module (max 23 cars)
char fn[24]; /* nom de la fonction appelee par un module (max 23 cars) - A REVOIR avec le int zero qui suit !! */
};
int zero2; /* permet de gerer la chaine precedente nom en sz */
/* */
long (*pop)(struct env * e, var *); /* utilise pour lire les parametres nommes dans les modules C */
/* table des caracteres de '000' a '999' (pour conversion) */
char tbl_1000[3000];
/* */
@@ -362,6 +369,20 @@ enum {
CMP_FOR = 10
};
enum {
FORMAT_TRIM = 1,
FORMAT_LEFT = 2,
FORMAT_RIGHT = 3,
FORMAT_CENTER = 4,
FORMAT_SURROUND = 5
};
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"
@@ -375,7 +396,10 @@ enum {
#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;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"
#define GOV_THIS "this"
#define GOV_PARENT "parent"
#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,@cr,@lf,@tab,@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,37,38,39,40,41,42,50,51,52,53,54,55,56"
#include "global.h"
+445 -65
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -30,86 +30,319 @@ Exemple :
2 series de cars en ET, "-" optionnel puis de 1 a 9 chiffres ou A B C D E F en OU
<1> = 0,1,2D ; 1,9,30-39:41:42:43:44:45:46 (separe par \n )
Ajout: gestion des etats. Permet d'activer une regle si l'etat courant est celui indique, et si la regle est ok, peut changer l'etat
nombre: etat1 > etat2 (1,10,0-9)
"nombre" ne sera testee que si l'etat en cours est 'etat1' ; si la regle "nombre" est verifiee, l'etat courant passa a 'etat2'
la gestion des etats est facultative, signifiant que sans rien c'est l'etat 0 qui est en cours/actif (= pas d'etat)
(la compilation remplace les noms des etats par leur indice d'apparition a l'envers, en commencant a 1)
Regles lex pour le format 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,*,#09-#7E] ;7; 1,1,3B;0,-1,09-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
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
etat: (0,24,0-9a-zA-Z) (1,1,#3E) (0,24,0-9a-zA-Z) ;3; 0,24,30-39:61-7A:41-5A;1,1,3E;0,24,30-39:61-7A:41-5A
debut: (1,1,#28) ;4; 1,1,28
fin: (1,1,#29) ;5; 1,1,29
occ: [1,9,0-9] (1,1,#2C) ;6; 1,9,30-39;1,1,2C
infini: (1,1,#2A) (1,1,#2C) ;7; 1,1,2A;1,1,2C
commentaire: (1,1,#3B) [0,*,#09-#7E] ;8; 1,1,3B;0,-1,09-7E
intervalle: (1,1,#2D) ;9; 1,1,2D
hexa: (1,1,#23) [2,2,0-9A-F] ;10; 1,1,23;2,2,30-39:41-46
car: (1,1,#21-#7E) ;12; 1,1,21-7E
reste: (1,1,#00-#FF) ;12; 1,1,00-FF
[] est remplace par () car cela revient au meme !
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
static char cLF = 10;
/*
blanc,1,nomregle,2,etat,3,debut,4,fin,5,occ,6,infini,7,commentaire,8,intervalle,9,hexa,10
car,11,reste,12
*/
//static char * nr[] = {"blanc", "nomregle", "etat", "debut", "fin", "occ", "infini", "commentaire", "intervalle", "hexa", "car", "reste"};
static struct {
ent16 blanc, nomregle, etat, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} rlex;
/*static void debug_valex(env * e, Dynamic * valex, Dynamic * tmp, Dynamic * tmp2)
{
int nbval = dynDcount(e, valex, cVM, 2, cFM);
for(int v = 1; v <= nbval; v++)
{
ent64 tok = dynFieldAsNumber(e, valex, 2, v, cFM, cVM);
dynField(e, valex, tmp, 1, v, cFM, cVM, 1);
hex2str(e, tmp, tmp2);
printf("%s/%lld:%s ", nr[tok - 1], tok, tmp2->mPtr);
}
printf("\n");
}*/
WAPIDECL 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, ';');
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, ';', ',', 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;
}
WAPIDECL void init_reg_lex(env * e, Dynamic * regles, Dynamic * tmp)
{
rlex.blanc = rg(e, regles, "blanc", tmp); // 1
rlex.nomregle = rg(e, regles, "nomregle", tmp); // 2
rlex.etat = rg(e, regles, "etat", tmp); // 3
rlex.debut = rg(e, regles, "debut", tmp); // 4
rlex.fin = rg(e, regles, "fin", tmp); // 5
rlex.occ = rg(e, regles, "occ", tmp); // 6
rlex.infini = rg(e, regles, "infini", tmp); // 7
rlex.commentaire = rg(e, regles, "commentaire", tmp); // 8
rlex.intervalle = rg(e, regles, "intervalle", tmp); // 9
rlex.hexa = rg(e, regles, "hexa", tmp); // 10
rlex.car = rg(e, regles, "car", tmp); // 11
rlex.reste = rg(e, regles, "reste", tmp); // 12
}
WAPIDECL long parse_lex(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours, int runtime)
{
#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, cLF, 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);
}
}
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
/*debug_valex(e, valex, tmp, encours);
dynSetLen(e, encours, 0);*/
/* */
ent16 n = 1, n_prem_et;
/* debut d'analyse des tokens : nomregle */
if(nreg(n) != rlex.nomregle)
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_RULENAME_EXPECTED;
}
n++;
if(nreg(n) == rlex.etat)
{
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
// encours: "etat1>etat2"
dynChange(e, encours, ">", ";", 1);
dynConcatSz(e, encours, ";", 1);
n++;
}
else
dynLet(e, encours, ";;", 1); /* equivalent a "pas d'etat" */
if(resultat->mLg == 0)
dynLet(e, resultat, "\n", 1);
dynStore(e, resultat, 1, nbres == 0 ? 2 : nbres * 2 , encours, cLF, ';');
/* liste de et/ou */
n_prem_et = n;
for(;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == rlex.debut || regle == rlex.car) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : car ou debut et/ou attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_CHAR_BRACKET_EXPECTED;
}
/* et */
if(n == n_prem_et)
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);
if(!runtime) printf("Erreur ligne %dc%s : occurence min/max attendue %d\n", numlig, tmp->mPtr, n);
return EXMOD_COMPILE_OCCURENCE_EXPECTED;
}
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
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);
hex2str(e, tmp, encours);
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);
/* TODO refactor conditions */
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 == rlex.car)
dynConcat(e, valex, tmp);
else
{
hex2str(e, tmp, encours);
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
{
hex2str(e, tmp, encours);
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);
hex2str(e, tmp, encours);
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);
if(!runtime) printf("Erreur ligne %dc%s : caractere/intervalle attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_CHAR_INTERVAL_EXPECTED;
}
if(n1 == rlex.fin) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : fin et/ou attendue\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_BRACKET_EXPECTED;
}
n += 2;
}
/* lecture nom regle en hexa */
dynField(e, valex, tmp, 1, 1, cFM, cVM, 1);
hex2str(e, tmp, trav);
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, ';', ',');
/* */
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, cLF, DYN_NONE);
/* */
#undef nreg
return OK;
}
#include "lex_files.h"
long regles_lex(env * e, Dynamic * r)
WAPIDECL long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
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);
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;
}
//
long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
long cr;
long cr = DYN_ERR;
if(fichier_lex != NULL)
{
/* selon fichier_lex, lire directement depuis le source */
if(strncmp(fichier_lex, "debuglex", 8) == 0)
{
if(*file_debuglex == 0)
#ifdef WINLIB
cr = dynRead(e, regles, "C:\\Users\\Poupougne42\\source\\repos\\win_w_src\\lex\\debuglex"); // lire les regles depuis le fichier sur disque
#else
cr = dynRead(e, regles, "/etc/wlanguage/debuglex"); // lire les regles depuis le fichier sur disque
#endif
else
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "wlex", 4) == 0)
{
if(*file_wlex == 0)
#ifdef WINLIB
cr = dynRead(e, regles, "C:\\Users\\Poupougne42\\source\\repos\\win_w_src\\lex\\wlex"); // lire les regles depuis le fichier sur disque
#else
cr = dynRead(e, regles, "/etc/wlanguage/wlex"); // lire les regles depuis le fichier sur disque
#endif
else
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "lexlex", 6) == 0)
{
cr = dynLet(e, regles, file_lexlex, DYN_LGNONE);
}
else
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 "," */
}
//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;
@@ -208,18 +441,20 @@ 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
elem detail : partie de la regle ET en cours
trouvemot, residu, motencours : utilise par la fonction de decodage en token lex()
valex (en sortie) : chaine/noregle/position ; saisie (en entree) : chaine a decoder */
Dynamic etregle, residu, motencours, trouvemot, elem, detail;
Dynamic etregle, residu, motencours, trouvemot, elem, detail, tabetat;
long eof = 0, trouveregle = 0, encours = 0, posaisie = 0, nbvalex = 0, iregle = 0;
long concorde = 0, postoken = 1; // position dans la chaine en entree de chaque token trouve
char car[3] = {0}, hexa[16] = {"0123456789ABCDEF"};
long nbetat;
short etat = *(short *)"0\0"; // etat en cours, par defaut 0 = pas d'etat (2 octets)
//
if(e == NULL || saisie == NULL || valex == NULL)
return;
@@ -234,6 +469,13 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynInit(e, &motencours, 0);
dynInit(e, &trouvemot, 0);
//
dynInit(e, &tabetat, 0);
dynRemove(e, regles, NULL, 0, DYN_TRUE);
dynRemove(e, regles, &tabetat, cLF, DYN_FALSE);
nbetat = dynDcount(e, &tabetat, ';', DYN_NONE, DYN_NONE); // securite
char ** petat = dynToTabPtr(e, &tabetat, ';');
/* maxi 99 etats sinon ko (car test sur 'short', 2 octets, pour les perfs) */
//
for(;;)
{
if(residu.mLg == 0)
@@ -281,6 +523,9 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynInsSz(e, valex, 2, nbvalex, Int64ToSz(e, trouveregle, FALSE, 0), DYN_LGNONE, cFM, cVM);
dynInsSz(e, valex, 3, nbvalex, Int64ToSz(e, postoken, FALSE, 0), DYN_LGNONE, cFM, cVM);
//
if(trouveregle * 2 < nbetat) // securite
etat = *(short *)petat[trouveregle * 2]; // nouvel etat courant suite a acceptation de la regle
//
if(motencours.mLg > trouvemot.mLg)
dynConcatSz(e, &residu, motencours.mPtr + trouvemot.mLg, motencours.mLg - trouvemot.mLg);
postoken += trouvemot.mLg/2;
@@ -300,10 +545,15 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynConcatSz(e, &motencours, car, 2);
iregle = 0;
dynRemove(e, regles, NULL, 0, DYN_TRUE);
dynRemove(e, regles, &etregle, 10, DYN_FALSE); /* ignorer la premiere ligne car contient le <numero,nom> des regles, separe par "," */
while(dynRemove(e, regles, &etregle, 10, DYN_FALSE) > -1)
dynRemove(e, regles, &etregle, cLF, DYN_FALSE); /* ignorer la premiere ligne car contient le <numero,nom> des regles, separe par "," + etats */
while(dynRemove(e, regles, &etregle, cLF, DYN_FALSE) > -1)
{
iregle++;
// gerer etat ici, pas dans "concorde_h"
if(iregle * 2 - 1 < nbetat)
if(etat != *(short *)petat[iregle * 2 - 1])
continue; // etat_pre incomptible : passer a la regle suivante
//
//
concorde = concorde_h(e, &motencours, &etregle, &elem, &detail);
//
@@ -341,6 +591,9 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynInsSz(e, valex, 2, nbvalex, Int64ToSz(e, trouveregle, FALSE, 0), DYN_LGNONE, cFM, cVM);
dynInsSz(e, valex, 3, nbvalex, Int64ToSz(e, postoken, FALSE, 0), DYN_LGNONE, cFM, cVM);
//
if(trouveregle * 2 < nbetat) // securite
etat = *(short *)petat[trouveregle * 2]; // nouvel etat courant suite a acceptation de la regle
//
if(motencours.mLg > trouvemot.mLg)
dynConcatSz(e, &residu, motencours.mPtr + trouvemot.mLg, motencours.mLg - trouvemot.mLg);
postoken += trouvemot.mLg/2;
@@ -360,7 +613,134 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynFree(e, &residu);
dynFree(e, &motencours);
dynFree(e, &trouvemot);
dynFree(e, &tabetat);
}
WAPIDECL long compile_maj_etat(env * e, Dynamic * resultat, Dynamic * res1, Dynamic * liste_etat, Dynamic * etat)
{
// resultat<1> (LF) => regle1,1,regle2,2,regle3,3;etatpre1;etatpost1;etatpre2;etatpost1;;etatpost2
dynField(e, resultat, res1, 1, DYN_NONE, cLF, DYN_NONE, 1);
// remplacer chaque etat par son indice (ordre d'apparition), 0 si vide
long nbe = 0, cptr, nbr = dynDcount(e, res1, ';', DYN_NONE, DYN_NONE);
dynSetLen(e, liste_etat, 0); // liste des etats, sans doublon
for(cptr = 2; cptr <= nbr; cptr++)
{
dynField(e, res1, etat, cptr, DYN_NONE, ';', DYN_NONE, 1);
if(etat->mLg == 0)
dynStoreSz(e, res1, cptr, DYN_NONE, "0", 1, ';', DYN_NONE);
else
{
long pos = dynLocateSz(e, liste_etat, etat->mPtr, ';', DYN_NONE, DYN_NONE);
if(pos == 0)
{
pos = (++nbe);
dynStore(e, liste_etat, pos, DYN_NONE, etat, ';', DYN_NONE);
if(nbe > 99)
return EXMOD_COMPILE_STATECOUNT_TOOBIG;
}
dynStoreSz(e, res1, cptr, DYN_NONE, Int64ToSz(e, pos, FALSE, 0), DYN_LGNONE, ';', DYN_NONE);
}
}
dynStore(e, resultat, 1, DYN_NONE, res1, cLF, DYN_NONE);
return 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, cLF, 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, 1); /* 1 = runtime on (appel depuis lexMod), pas de printf */
}
if(ret == OK)
ret = compile_maj_etat(e, compile, &tmp, &tmp1, &tmp2);
cr = ret;
}
//
dynFree(e, &regles);
dynFree(e, &tmp);
dynFree(e, &ligne);
dynFree(e, &tmp1);
dynFree(e, &tmp2);
dynFree(e, &tmp3);
//
return cr;
}
WAPIDECL long compile_like(env * e, Dynamic * like, Dynamic * compile)
{
/* compile la chaine donnee par "like" (foreach dynamic/hashtable) ; regles =>
'*' a remplacer par [0,*,0-9a-zA-Z] => 0,-1,30-39:61-7A:41-5A
'+' a remplacer par [1,*,0-9a-zA-Z] => 1,-1,30-39:61-7A:41-5A
'?' : remplace une lettre [1,1,0-9a-zA-Z] => 1,1,30-39:61-7A:41-5A
'X' : chaque lettre/chiffre par [1,1,58] => 1,1,58
les autres caracteres sont ignores (si Dynamic, autoriser les autres ??)
concatener avec des ';' => like,1,other,2;0;0;0;0\n0,-1,30-39:61-7A:41-5A;2,2,58;0,-1,30-39:61-7A:41-5A\n1,1,00-FF pour l'exemple
*/
dynSetLen(e, compile, 0);
/* */
octet c;
long i, n = 0;
for(i = 0; i < like->mLg; i++)
{
c = like->ptr[i];
if(c == '*')
dynStoreSz(e, compile, ++n, DYN_NONE, "0,-1,30-39:61-7A:41-5A", 22, ';', DYN_NONE);
else if(c == '+')
dynStoreSz(e, compile, ++n, DYN_NONE, "1,-1,30-39:61-7A:41-5A", 22, ';', DYN_NONE);
else if(c == '?')
dynStoreSz(e, compile, ++n, DYN_NONE, "1,1,30-39:61-7A:41-5A", 21, ';', DYN_NONE);
else if((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z'))
{
dynStoreSz(e, compile, ++n, DYN_NONE, "1,1,", 21, ';', DYN_NONE);
dynConcatSz(e, compile, dynConvertCharToCharHexa(c), 2);
}
}
if(compile->mLg == 0)
{
/* cas particulier */
return DYN_ERR;
}
else
{
/* ajout necessaire au compile lex */
dynInsSz(e, compile, 1, DYN_NONE, "like,1,other,2;0;0;0;0", 22, cLF, DYN_NONE);
dynConcatSz(e, compile, "\n1,1,00-FF", cLF);
return DYN_OK;
}
}
/*
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 : hex2str(e, hexa, clair);
*/
/* source OK :
* LEX.REGLE = regles Lex, valeurs ET separees par "," ; liste de cars en OU pour chaque partie ET
LEX.REGLE = ""
+49
View File
@@ -0,0 +1,49 @@
/* **********************************************
__ __ __
\ \/ \/ / 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
#define EXMOD_COMPILE_RULENAME_EXPECTED 1
#define EXMOD_COMPILE_CHAR_BRACKET_EXPECTED 2
#define EXMOD_COMPILE_OCCURENCE_EXPECTED 3
#define EXMOD_COMPILE_CHAR_INTERVAL_EXPECTED 4
#define EXMOD_COMPILE_BRACKET_EXPECTED 5
#define EXMOD_COMPILE_STATECOUNT_TOOBIG 6
#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, int runtime);
/* */
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 rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp);
WAPIDECL long compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile);
WAPIDECL long compile_maj_etat(env * e, Dynamic * resultat, Dynamic * res1, Dynamic * liste_etat, Dynamic * etat);
WAPIDECL long compile_like(env * e, Dynamic * like, Dynamic * compile);
#endif
+256
View File
@@ -0,0 +1,256 @@
/* **********************************************
__ __ __
\ \/ \/ / 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"
#include "var.h"
#include "hashtable.h"
#include "convert.h"
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
/* codes erreur dans dans lex.h */
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Rule name expected",
"Bracket character expected",
"Number of occurence expected",
"Character interval expected",
"Bracket expected", // 5
"State count too big"
};
/* ============================================================================================= */
#include "mod.c"
#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 */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "compile", 7))
{
/* get param in the right order */
var * paramLexRules = getParam(e, "lexRules", 8);
var * paramCompiledRules = getParam(e, "compiledRules", 13);
var * paramRulesNameSet = getParam(e, "rulesNameSet", 12);
if(paramLexRules == NULL || paramCompiledRules == NULL)
exc = EX_MODPARAM;
else if(paramLexRules->type != VAR_DYNAMIC || paramCompiledRules->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, compile_lex(e, paramLexRules, paramCompiledRules));
if(exc == OK && paramRulesNameSet != NULL)
{
if(paramRulesNameSet->type != VAR_HASHTABLE)
var_let(e, paramRulesNameSet, &e->int_hash, FALSE, FALSE);
var * v = &e->int_number;
hashtable_clear(e, paramRulesNameSet);
long cpt, nb = dynDcount(e, paramCompiledRules, ',', 1, 10);
for(cpt = 1; cpt < nb;)
{
dynField(e, paramCompiledRules, &e->tmp_dynamic, 1, cpt++, 10, ',', 1);
e->int_number.num = dynFieldAsNumber(e, paramCompiledRules, 1, cpt++, 10, ',') * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, paramRulesNameSet, copy_nom(e, e->tmp_dynamic.mPtr), &v);
}
}
}
}
else if(modFnIs(e, "analyze", 7))
{
/* get param in the right order */
var * paramCompiledRules = getParam(e, "compiledRules", 13);
var * paramValue = getParam(e, "value", 5);
var * paramTokenList = getParam(e, "tokenList", 9);
if(paramCompiledRules == NULL || paramValue == NULL || paramTokenList == NULL)
exc = EX_MODPARAM;
else if(paramCompiledRules->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramTokenList->type != VAR_DYNAMIC)
var_let(e, paramTokenList, &e->int_dynamic, FALSE, FALSE);
lex(e, paramCompiledRules, paramValue, paramTokenList);
}
}
else if(modFnIs(e, "getToken", 8))
{
/* get param in the right order */
var * paramTokenList = getParam(e, "tokenList", 9);
var * paramTokenIndex = getParam(e, "tokenIndex", 10);
var * paramTokenSet = getParam(e, "tokenSet", 8);
if(paramTokenList == NULL || paramTokenIndex == NULL || paramTokenSet == NULL)
exc = EX_MODPARAM;
else if(paramTokenList->type != VAR_DYNAMIC || (paramTokenIndex->type != VAR_NUMBER && paramTokenIndex->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
/* ne pas vider la hash, juste ecrire 3 elements : ruleValue, ruleNumber, ruleLocation */
number indice;
if( ! var_conv_num(e, paramTokenIndex, &indice))
exc = EX_MODPARAM;
else
{
if(paramTokenSet->type != VAR_HASHTABLE)
{
var_let(e, paramTokenSet, &e->int_hash, FALSE, FALSE);
hashtable_clear(e, paramTokenSet);
}
indice /= NUM_FACTEUR;
var * n = &e->int_number;
n->num = dynExtractSubFieldAsNumber(e, paramTokenList, 2, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenNumber"), &n);
/* */
var * v = &e->int_dynamic, * w = &e->tmp_dynamic;
if(n->num == 0)
dynSetLen(e, v, 0);
else
{
dynExtractSubField(e, paramTokenList, 1, indice, w);
hex2str(e, w, v);
}
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenValue"), &v);
/* */
if(n->num != 0)
n->num = dynExtractSubFieldAsNumber(e, paramTokenList, 3, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenLocation"), &n);
}
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+162 -6
View File
@@ -1,8 +1,164 @@
//static char file_debuglex[] = "";
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\n1,2,61-7A:41-5A\n1,1,3F\n1,9,30-39\n1,1,2B\n1,1,2D\n1,1,3A;1,1,61-7A:41-5A:5F;0,23,61-7A:41-5A:30-39\n1,1,2E;1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,00-FF";
// !! ne pas mettre de caracteres \r dans les constantes ci-dessous !!
//static char file_wlex[] = "";
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,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\n"
"1,-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\n1,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\n1,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\n1,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\n1,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\n1,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\n1,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,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\n1,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,3F\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\n1,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";
// 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;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\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";*/
static char file_lexlex[] = "blanc,1,nomregle,2,etat,3,debut,4,fin,5,occ,6,infini,7,commentaire,8,intervalle,9,hexa,10,car,11,reste,12;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n"
"1,-1,20:09\n"
"1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n"
"0,24,41-5A;1,1,3E;0,24,41-5A\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,20-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;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\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";
*/
//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,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102\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\n1,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\n1,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\n1,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\n1,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\n1,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\n1,1,73;1,1,71;1,1,72;1,1,74\n1,1,65;1,1,78;1,1,70\n1,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\n1,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\n1,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\n1,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";
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,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n"
"1,-1,20:09\n"
"1,1,3B;0,-1,00-FF\n"
"1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n"
"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\n"
"1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n"
"1,1,65;1,1,6E;1,1,64\n"
"1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n"
"1,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\n"
"1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n"
"1,1,73;1,1,75;1,1,62\n"
"1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n"
"1,1,69;1,1,66\n"
"1,1,74;1,1,68;1,1,65;1,1,6E\n"
"1,1,65;1,1,6C;1,1,73;1,1,65\n"
"1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n"
"1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n"
"1,1,64;1,1,6F\n"
"1,1,63;1,1,61;1,1,6C;1,1,6C\n"
"1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n"
"1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n"
"1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n"
"1,1,6C;1,1,6F;1,1,6F;1,1,70\n"
"1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n"
"1,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\n"
"1,1,6C;1,1,69;1,1,6B;1,1,65\n"
"1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n"
"1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n"
"1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n"
"1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n"
"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\n"
"1,1,6E;1,1,6F;1,1,70\n"
"1,1,70;1,1,61;1,1,72;1,1,74\n"
"1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n"
"1,1,65;1,1,63;1,1,68;1,1,6F\n"
"1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n"
"1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n"
"1,1,6C;1,1,65;1,1,74\n"
"1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n"
"1,1,6E;1,1,65;1,1,77\n"
"1,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\n"
"1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n"
"1,1,68;1,1,6F;1,1,6C;1,1,64\n"
"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\n"
"1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n"
"1,1,69;1,1,6E;1,1,74\n"
"1,1,66;1,1,72;1,1,61;1,1,63\n"
"1,1,61;1,1,62;1,1,73\n"
"1,1,6E;1,1,65;1,1,67\n"
"1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,73;1,1,71;1,1,72;1,1,74\n"
"1,1,65;1,1,78;1,1,70\n"
"1,1,74;1,1,79;1,1,70;1,1,65\n"
"1,1,6C;1,1,65;1,1,6E\n"
"1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n"
"1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n"
"1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n"
"1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n"
"1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,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\n"
"1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n"
"1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n"
"1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n"
"1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n"
"1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n"
"1,1,3D\n"
"1,1,23\n"
"1,1,3E\n"
"1,1,3C\n"
"1,1,3E;1,1,3D\n"
"1,1,3C;1,1,3D\n"
"1,1,61;1,1,6E;1,1,64\n"
"1,1,6F;1,1,72\n"
"1,1,6E;1,1,6F;1,1,74\n"
"1,1,28\n"
"1,1,29\n"
"1,1,7B\n"
"1,1,7D\n"
"1,1,5B\n"
"1,1,5D\n"
"1,1,21\n"
"1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n"
"1,1,22;0,765,20-21:23-EF;1,1,22\n"
"1,1,27;0,765,20-26:28-EF;1,1,27\n"
"1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n"
"1,1,40;1,-1,61-7A\n"
"1,13,30-39;1,1,2E;0,5,30-39\n"
"1,13,30-39\n"
"1,1,2D\n"
"1,1,2B\n"
"1,1,2A\n"
"1,1,2F\n"
"1,1,5C\n"
"1,1,25\n"
"1,1,3A\n"
"1,1,2C\n"
"1,1,2E\n"
"1,1,26\n"
"1,1,00-FF";
+85 -67
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.
@@ -29,24 +29,29 @@
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "lzw.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextLzw cl;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -57,122 +62,135 @@ 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
// - - - - - - - - - - - - - - - - - - - -
/* 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 */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initLzw(e, &p_etat->cl);
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initLzw(e, &p_etat->cl);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeLzw(e, &p_etat->cl);
//*** FIN du code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == 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
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
/* compression du clair de param, en une fois */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPlaintextThenCompressed = getParam(e, "plaintextThenCompressed", 23);
if(paramPlaintextThenCompressed == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
else if(paramPlaintextThenCompressed->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, setLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
exc = setError(p_etat, setLzw(e, paramPlaintextThenCompressed, &p_etat->cl, 0)); /* compression compatible PDF (mais pas GIF), 0 : en une fois */
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
/* decompression du code de param, en une fois */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramCompressedThenPlaintext = getParam(e, "compressedThenPlaintext", 23);
var * paramReverse = getParam(e, "reverse", 7);
if(paramCompressedThenPlaintext == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
else if(paramCompressedThenPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
p_etat->cl.inverse = FALSE;
if(param2 != NULL)
if(paramReverse != NULL)
{
if(param2->type == VAR_DYNAMIC || param2->type == VAR_NUMBER)
if(paramReverse->type == VAR_DYNAMIC || paramReverse->type == VAR_NUMBER)
{
number inv;
if(var_conv_num(e, param2, &inv))
if(var_conv_num(e, paramReverse, &inv))
p_etat->cl.inverse = (inv != 0 ? TRUE : FALSE);
}
}
exc = setError(p_etat, getLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
exc = setError(p_etat, getLzw(e, paramCompressedThenPlaintext, &p_etat->cl, 0)); /* decompression compatible PDF (et GIF si reverse = TRUE), 0 : en une fois */
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
/* **************************************************************************************************** */
+50
View File
@@ -0,0 +1,50 @@
/* **********************************************
__ __ __
\ \/ \/ / 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/>.
********************************************** */
/* est inclus dans tous les modules xxxMod.c */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
static var * getParam(env * e, const char * name, int lg)
{
/* recherche parametre nomme "name" */
var * p = &e->v;
p->type = VAR_NULL;
e->nom64[0] = 0; e->nom64[1] = 0; e->nom64[2] = 0;
if(lg > 0 && lg < 25)
strncpy((char *)e->nom64, name, lg);
(e->pop)(e, p);
if(p->type == VAR_PARAM)
return (var *)(p->ptr);
else
{
if(e->exception == EX_BUFOVF)
e->exception = OK; /* parametre non trouve : exception BUFOVF => pas d'exception, gere avec le retour NULL ici, par l'appelant */
return NULL;
}
}
+236
View File
@@ -0,0 +1,236 @@
//ent64 ENT64_MAX = 999999999999999999ull; /* 18 chiffres dont 5 decimales */
//ent32 FACTEUR = 100000;
ent64 mul64(ent64s a, ent64s b, ent64s * r)
{
/* recherche signe du resultat + passage en positif */
int negatif = 0;
if(a < 0)
{
negatif = 1 - negatif;
a = -a;
}
if(b < 0)
{
negatif = 1 - negatif;
b = -b;
}
/* multiplication */
ent64 ap = a, bp = b;
ent64 aph = (ap >> 32), apl = (ap & 0xFFFFFFFFull);
ent64 bph = (bp >> 32), bpl = (bp & 0xFFFFFFFFull);
ent64 ab_hi = aph * bph;
ent64 ab_lo = apl * bpl;
ent64 ab_lo_debut = ab_lo;
ent64 aphbpl = aph * bpl;
ent64 aplbph = apl * bph;
ab_hi += (aphbpl >> 32) + (aplbph >> 32); /* pas d'overflow ! */
ent64 sum = (aphbpl & 0xFFFFFFFFull) + (aplbph & 0xFFFFFFFFull); /* si overflow ici (quad haut non nul), increment ab_hi */
ab_hi += (sum >> 32);
ab_lo += (sum & 0xFFFFFFFFull) << 32; /* si overflow ici, incrementer ab_hi ; en non signe c'est le test avec inferieur qui suit ! */
if(ab_lo < ab_lo_debut)
ab_hi++; /* retenue */
/* division par le facteur 100000 */
ent64 ab_hi_hi = (ab_hi >> 32);
ent64 ab_hi_lo = (ab_hi & 0xFFFFFFFF);
ent64 ab_lo_hi = (ab_lo >> 32);
ent64 ab_lo_lo = (ab_lo & 0xFFFFFFFF);
ent32 q_hi_hi = ab_hi_hi / FACTEUR;
ent64 reste = ab_hi_hi % FACTEUR;
ent32 q_hi_lo = ((reste << 32) | ab_hi_lo) / FACTEUR;
reste = ((reste << 32) | ab_hi_lo) % FACTEUR;
ent32 q_lo_hi = ((reste << 32) | ab_lo_hi) / FACTEUR;
reste = ((reste << 32) | ab_lo_hi) % FACTEUR;
ent32 q_lo_lo = ((reste << 32) | ab_lo_lo) / FACTEUR;
reste = ((reste << 32) | ab_lo_lo) % FACTEUR;
ab_hi = ((ent64)q_hi_hi << 32) | (ent64)q_hi_lo;
ab_lo = ((ent64)q_lo_hi << 32) | (ent64)q_lo_lo;
/* si reste >= FACTEUR/2 => faire +1, ce qui revient a tester >= au lieu de > */
/* test final */
if(ab_hi > 0)
return EX_NUMOVF; /* overflow */
if(reste >= FACTEUR / 2)
{
if(ab_lo >= ENT64_MAX)
return EX_NUMOVF; /* overflow */
else
ab_lo++;
}
else if(ab_lo > ENT64_MAX)
return EX_NUMOVF; /* overflow */
/* */
if(negatif)
*r = -(ent64s)ab_lo;
else
*r = (ent64s)ab_lo;
return OK; /* pas d'overflow */
}
ent64 div64(ent64s a, ent64s b, ent64s * q, ent64s * r, int div_ent)
{
if(b == 0)
return EX_DIV0;
/* a/b => a * 100000 / b ; div_ent # 0 si division entiere (methode ici evite l'algorithme de Knuth D en base 2^32) */
/* gerer les signes => travail en positif (idem multiplication) */
int negatif = 0, divid_neg = 0;
if(a < 0)
{
negatif = 1 - negatif;
a = -a;
divid_neg = 1;
}
if(b < 0)
{
negatif = 1 - negatif;
b = -b;
}
ent64 ap = a, bp = b;
ent64 q_lo = ap / bp;
ent64 reste_debut = ap % bp;
if(q_lo > ENT64_MAX / FACTEUR)
return EX_NUMOVF;
q_lo *= FACTEUR;
ent64 reste = reste_debut;
if( ! div_ent)
{
ent64 reste10;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 10000ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 1000ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 100ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 10ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp);
reste = reste10 % bp;
if(reste >= bp - reste)
{
if(q_lo >= ENT64_MAX)
return EX_NUMOVF;
else
q_lo++;
}
}
if(q)
{
if(negatif)
*q = -(ent64s)q_lo;
else
*q = (ent64s)q_lo;
}
/* reste est du signe du dividende (si demande en parametre) */
if(r)
{
if(divid_neg)
*r = -(ent64s)reste;
else
*r = (ent64s)reste;
}
///* multiplication par 100000 */
//ent64 ap = a, bp = b;
//ent64 a_hi = (ap >> 32) * FACTEUR;
//ent64 a_lo = (ap & 0xFFFFFFFFull) * FACTEUR;
//ent64 a_lo_debut = a_lo;
//a_lo += (a_hi << 32);
//a_hi >>= 32;
//if(a_lo < a_lo_debut)
// a_hi++;
///* division par b */
//ent64 reste = a_hi;
//ent32 a_lo_hi = a_lo >> 32;
//ent32 a_lo_lo = a_lo & 0xFFFFFFFFull;
//ent64 q_hi = ((ent64)reste << 32) | a_lo_hi;
//reste = q_hi % bp;
//q_hi /= bp;
//ent64 q_lo = ((ent64)reste << 32) | a_lo_lo;
//reste = q_lo % bp;
//q_lo /= bp;
///* */
//if(q_hi > 0)
// return EX_NUMOVF; /* overflow */
//if(reste >= bp - reste)
//{
// if(q_lo >= ENT64_MAX)
// return EX_NUMOVF; /* overflow*/
// else
// q_lo++; /* arrondi superieur */
//}
//else if(q_lo > ENT64_MAX)
// return EX_NUMOVF; /* overflow */
///* gerer les signes du quotient (si demande en parametre) */
//if(q)
//{
// if(negatif)
// *q = -(ent64s)q_lo;
// else
// *q = (ent64s)q_lo;
//}
///* reste est du signe du dividende (si demande en parametre) */
//if(r)
//{
// if(divid_neg)
// *r = -(reste / FACTEUR);
// else
// *r = reste / FACTEUR;
//}
return OK;
}
ent64 add64(ent64s a, ent64s b, ent64s * s)
{
ent64 r;
if(a >= 0 && b >= 0)
{
r = (ent64)a + (ent64)b;
if(r > ENT64_MAX || r < (ent64)a)
return EX_NUMOVF; /* overflow*/
else
*s = (ent64s)r;
}
else if (a < 0 && b < 0)
{
r = (ent64)(- a) + (ent64)(- b);
if(r > ENT64_MAX || r < (ent64)(- a))
return EX_NUMOVF; /* overflow*/
else
*s = - (ent64s)r;
}
else
{
*s = a + b; /* pas d'overflow possible avec signes differents */
}
return OK;
}
ent64 sub64(ent64s a, ent64s b, ent64s * s)
{
ent64 r;
if(a >= 0 && b < 0)
{
r = (ent64)a + (ent64)(- b);
if(r > ENT64_MAX || r < (ent64)a)
return EX_NUMOVF; /* overflow*/
else
*s = (ent64s)r;
}
else if (a < 0 && b >= 0)
{
r = (ent64)(- a) + (ent64)(b);
if(r > ENT64_MAX || r < (ent64)(b))
return EX_NUMOVF; /* overflow*/
else
*s = - (ent64s)r;
}
else
{
*s = a - b; /* pas d'overflow possible avec signes egaux */
}
return OK;
}
+8 -2
View File
@@ -54,11 +54,13 @@ 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) */
Dynamic mImg; /* images en FM, en hexa, BMP 24/32 bpp uniquement (codage RGB) */
Dynamic mInfoPage; /* quand nb pages pas connu a l'init, contient le num obj de chaque page */
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 mNbFont, mNbImg, mNbObjFixe;
long mNumPage; /* numero page en cours */
long mLmarg; /* marge gauche en mm x 10 */
@@ -68,7 +70,9 @@ typedef struct
long mDimFont; /* taille fonte */
long mDimFontCadre;
long mDimLig;
Dynamic mFont; /* nom des 14 fontes standards */
Dynamic mFont; /* nom des 14 fontes standards */
Dynamic mEan128; /* codage graphique du cab ean128 */
modContextLzw mCtxLzw; /* gestion compression page lzw */
@@ -83,7 +87,9 @@ 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 setCab128(env * e, modContextPdf * ctxPdf, Dynamic * data, long x, long y, long h);
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 pdfLoadImageGif(env * e, modContextPdf * ctxPdf, Dynamic * fichier);
WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic * lignes, long format);
+215 -159
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.
@@ -30,25 +30,35 @@
#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;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_PDF_INTERNAL_ERR = 1,
EXMOD_PDF_IMGFORMAT = 2,
EXMOD_PDF_PARAMETERSET = 3,
EXMOD_NB = 3
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Internal error",
"Image format unsupported (BMP/GIF only)",
"Incorrect parameterSet's membre"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -59,38 +69,31 @@ 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
// - - - - - - - - - - - - - - - - - - - -
/* 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 */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initPdf(e, &p_etat->cp);
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initPdf(e, &p_etat->cp);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
@@ -98,278 +101,331 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
//*** code specifique ici
freePdf(e, &p_etat->cp);
// fin liberation specifique module avant arret process
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == 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
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "beginDoc", 8))
{
// nouveau document pdf
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
else if(paramPdfParameterSet->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);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Title"), &titre);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Fonts"), &fontes);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Pages"), &nbPage);
hashtable_do(e, HASH_READ, paramPdfParameterSet, 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)
if(titre->type == VAR_DYNAMIC && fontes->type == VAR_DYNAMIC &&
(nbPage->type == VAR_NUMBER || nbPage->type == VAR_DYNAMIC) && (format->type == VAR_NUMBER || format->type == VAR_DYNAMIC))
{
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));
exc = setError(p_etat, newPdf(e, &p_etat->cp, titre, nnbPage / NUM_FACTEUR, nformat / NUM_FACTEUR, fontes) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
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)
/* get param in the right order */
var * paramPdfContent = getParam(e, "pdfContent", 10);
if(paramPdfContent == 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);
var_let(e, paramPdfContent, getPdf(e, &p_etat->cp), FALSE, FALSE);
exc = setError(p_etat, cr ? OK : EXMOD_PDF_INTERNAL_ERR);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
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 ?
/* get param in the right order */
// ajouter la page en cours au doucment pdf
exc = setError(p_etat, setPdfPage(e, &p_etat->cp, 1) ? OK : EXMOD_PDF_INTERNAL_ERR); // 1 = avec compression ; parametrer ?
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addText", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
var * paramString = getParam(e, "string", 6);
if(paramPdfParameterSet == NULL || paramString == NULL)
exc = EX_MODPARAM;
else if(param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramString->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);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Font"), &fonte);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Size"), &taille);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Color"), &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
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, paramString) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
else if(modFnIs(e, "delImage", 8))
/* ---------------------------------------------------- */
else if(modFnIs(e, "addCab128", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
var * paramString = getParam(e, "string", 6);
if(paramPdfParameterSet == NULL || paramString == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER && param1->type != VAR_DYNAMIC)
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramString->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));
// ajouter le texte
var * x, * y, * h; // position et hauteur du CAB
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
if(x && y && h)
{
number nx, ny, nh;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, h, &nh) )
exc = setError(p_etat, setCab128(e, &p_etat->cp, paramString, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nh / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addGraph", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
else if(paramPdfParameterSet->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);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "StrokeColor"), &couleurTrait);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "FillColor"), &couleurRemplissage);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "LineThickness"), &epaisseur);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Dotted"), &pointille);
hashtable_do(e, HASH_READ, paramPdfParameterSet, 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));
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) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addImage", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
else if(paramPdfParameterSet->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);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "ImageIndex"), &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));
exc = setError(p_etat, setPdfImage(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nimg / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "loadImage", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramImage = getParam(e, "image", 5);
var * paramFormat = getParam(e, "format", 6);
if(paramImage == NULL || paramFormat == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
else if(paramImage->type != VAR_DYNAMIC || paramFormat->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, ! pdfLoadImageBmp(e, &p_etat->cp, param1));
if(dynCompare(e, paramFormat, CMP_EQ, "BMP", 3))
exc = setError(p_etat, pdfLoadImageBmp(e, &p_etat->cp, paramImage) ? OK : EXMOD_PDF_INTERNAL_ERR);
else if(dynCompare(e, paramFormat, CMP_EQ, "GIF", 3))
exc = setError(p_etat, pdfLoadImageGif(e, &p_etat->cp, paramImage) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_IMGFORMAT);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "delImage", 8))
{
/* get param in the right order */
var * paramImage = getParam(e, "imageIndex", 10);
if(paramImage == NULL)
exc = EX_MODPARAM;
else if(paramImage->type != VAR_NUMBER && paramImage->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number indice;
if(var_conv_num(e, paramImage, &indice))
exc = setError(p_etat, pdfDeleteImage(e, &p_etat->cp, indice / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ---------------------------------------------------- */
else if(modFnIs(e, "listing", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
var * paramTextThenPdfContent = getParam(e, "textThenPdfContent", 18);
if(paramPdfParameterSet == NULL || paramTextThenPdfContent == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramTextThenPdfContent->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);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Title"), &titre);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Format"), &format);
if(titre && format)
{
if(titre->type == VAR_DYNAMIC && format->type == VAR_NUMBER)
if(titre->type == VAR_DYNAMIC && (format->type == VAR_NUMBER || format->type == VAR_DYNAMIC))
{
int cr = pdfList(e, &p_etat->cp, titre, param2, format->num / NUM_FACTEUR);
if(cr)
number nformat;
if( var_conv_num(e, format, &nformat) )
{
var_let(e, param2, getPdf(e, &p_etat->cp), FALSE, FALSE);
int cr = pdfList(e, &p_etat->cp, titre, paramTextThenPdfContent, nformat / NUM_FACTEUR);
if(cr)
var_let(e, paramTextThenPdfContent, getPdf(e, &p_etat->cp), FALSE, FALSE);
exc = setError(p_etat, cr ? OK : EXMOD_PDF_INTERNAL_ERR);
}
exc = setError(p_etat, ! cr);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+426 -28
View File
@@ -22,6 +22,8 @@
********************************************** */
#include "pdf.h"
#include <string.h>
// force exporting
#ifdef WINLIB
#undef WAPIDECL
@@ -169,6 +171,69 @@ enum {
};
/* valeur en dixieme de mm * CONV11 / CONV2 = valeur en unites pdf x 100 (72 dpi = 72 points par pouce ; 1 pouce = 25.4) */
// dynOconv ne sert pas ailleurs : a voir a mettre dans conv.h ? autre ? (revoir mod Horodate)
#include "time.h"
static long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format)
{
/* a revoir pour UTF8 ? (Base64 ?) oui pour D car d'autres cars utf8 peuvent etre dans la chaine */
char tmp[5];
//
switch(*format++)
{
case 'D': // obsolete ? utiliser le mod Horodate
{
struct tm * ptm;
/* conversion date/heure : format interne = time_t unix sur 32 bits */
time_t tm;
if(this->mLg == 0)
{
tm = time(NULL);
ptm = gmtime(&tm);
}
else
{
tm = dynToNum(e, this, DYN_NONE, 10); /* pas de signe, lg max sur 32 bits = 10 chiffres */
if(this->mInternal == DYN_ERR)
return DYN_ERR; /* pbm de conversion numerique */
ptm = localtime(&tm);
}
/* analyse formatage demande */
dynLet(e, resultat, NULL, DYN_LGNONE);
tmp[1] = 0;
while((tmp[0] = *format++))
switch(tmp[0])
{
case 'Y':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_year + 1900, DYN_NONE, 4), 4);
break;
case 'y':
dynConcatSz(e, resultat, Int32ToSz((ptm->tm_year + 1900) % 100, DYN_NONE, 2), 2);
break;
case 'M':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mon + 1, DYN_NONE, 2), 2);
break;
case 'D':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mday, DYN_NONE, 2), 2);
break;
case 'h':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_hour, DYN_NONE, 2), 2);
break;
case 'm':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_min, DYN_NONE, 2), 2);
break;
case 's':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_sec, DYN_NONE, 2), 2);
break;
default:
dynConcatSz(e, resultat, tmp, 1);
break;
}
break;
}
}
return DYN_OK;
}
/* PRIVATE *****************************************************/
static int pdfEchap(env * e, Dynamic * resultat, Dynamic * chaine)
{
@@ -201,6 +266,13 @@ static int setXref(env * e, modContextPdf * ctxPdf)
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 int majXref(env * e, modContextPdf * ctxPdf, int numObj)
{
/* MAJ table xref quand l'objet est mis "apres" la declaration */
dynLet(e, &ctxPdf->mTmp3, Int64ToSz(e, (ent64s)ctxPdf->mPdf.mLg, FALSE, 10), 10);
return dynStore(e, &ctxPdf->mXref, numObj + 1, DYN_NONE, &ctxPdf->mTmp3, cFM, DYN_NONE);
}
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"
@@ -272,6 +344,33 @@ static void convertHexaRGBToBinLzw(env * e, modContextPdf * ctxPdf)
setLzw(e, &ctxPdf->mTmp2, &ctxPdf->mCtxLzw, 0);
}
static void graphCab128(env * e, modContextPdf * ctxPdf, long code, long * x, long y, long h)
{
long ec = 0, x1, i, largeur = 3; /* largeur des barres, pour un 1 */
long nb = (code == 106 ? 13 : 11); /* code stop = 13 bits, les autres = 11 bits */
code = code * 11;
for(i = 0; i < nb; i++, code++)
{
if(ctxPdf->mEan128.mPtr[code] == '1')
{
if( ! ec)
{
ec = 1;
x1 = *x;
}
}
else if(ec)
{
ec = 0;
setPdfGraph(e, ctxPdf, 'R', x1, y, *x - x1, h, -1, RGB(0,0,0), 0, 0);
}
/* */
*x += largeur;
}
if(ec)
setPdfGraph(e, ctxPdf, 'R', x1, y, *x - x1, h, -1, RGB(0,0,0), 0, 0);
}
/* PUBLIC ************************************************************************/
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf)
{
@@ -292,12 +391,32 @@ WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf)
ctxPdf->mPdf.type = VAR_DYNAMIC;
dynInit(e, &ctxPdf->mXref, 1024);
dynInit(e, &ctxPdf->mImg, 2048);
dynInit(e, &ctxPdf->mInfoPage, 1024);
dynInit(e, &ctxPdf->mEan128, 1200);
/* 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);
//
// code ean 128 : https://fr.wikipedia.org/wiki/Code_128
// Checksum = (StartCode + 1 x valeur1 + 2 x valeur2 + 3 x valeur3 + ...) modulo 103 (valeur de 0 a 102)
dynLet(e, &ctxPdf->mEan128,
"11011001100110011011001100110011010010011000100100011001000100110010011001000100110001001000110010011001001000" // 0 9
"11001000100110001001001011001110010011011100100110011101011100110010011101100100111001101100111001011001011100" // 10 19
"11001001110110111001001100111010011101101110111010011001110010110011100100110111011001001110011010011100110010" // 20 29
"11011011000110110001101100011011010100011000100010110001000100011010110001000100011010001000110001011010001000" // 30 39
"11000101000110001000101011011100010110001110100011011101011101100010111000110100011101101110111011011010001110" // 40 49
"11000101110110111010001101110001011011101110111010110001110100011011100010110111011010001110110001011100011010" // 50 59
"11101111010110010000101111000101010100110000101000011001001011000010010000110100001011001000010011010110010000" // 60 69
"10110000100100110100001001100001010000110100100001100101100001001011001010000111101110101100001010010001111010" // 70 79
"10100111100100101111001001001111010111100100100111101001001111001011110100100111100101001111001001011011011110" // 80 89
"11011110110111101101101010111100010100011110100010111101011110100010111100010111101010001111010001010111011110" // 90 99
"1011110111011101011110111101011101101000010011010010000110100111001100011101011", 1180); // 100 106 (106 sur 13 bits au lieu de 11 pour tous les autres)
// codes 0 - 94 : codes ascii de 32 a 126 (code 128B)
// codes 95:DEL 96:FNC3 97:FNC2 98:SHIFTA 99:CODEC 100:CODEB 101:CODEA 102:FNC1 103:StartA 104:StartB 105:StartC 106:Stop(13 bits)
// code EAN128B : startB_104 + valeur1 + valeur2 + valeur3 + ... + checksum + Stop_106
}
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf)
@@ -312,15 +431,17 @@ WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf)
dynFree(e, &ctxPdf->mPdf);
dynFree(e, &ctxPdf->mXref);
dynFree(e, &ctxPdf->mImg);
dynFree(e, &ctxPdf->mInfoPage);
dynFree(e, &ctxPdf->mEan128);
}
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;
long nb_img, nb_obj_entete, nb_font;
int cr = TRUE;
/* controles */
if(nb_page < 1)
if(nb_page < 0)
return FALSE;
/* */
switch(format)
@@ -360,9 +481,11 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
/* */
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->mNbObjFixe = 3;
nb_obj_entete = ctxPdf->mNbObjFixe + nb_font + nb_img;
ctxPdf->mNbObj = nb_obj_entete + ctxPdf->mNbPage;
ctxPdf->mNumPage = 0;
ctxPdf->mNbImg = nb_img;
//
dynLet(e, &ctxPdf->mPdf, "%PDF-1.2\r\n", DYN_LGNONE);
// objet racine root
@@ -374,24 +497,27 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
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");
dynOconv(e, &ctxPdf->mTmp1, &ctxPdf->mTmp2, "DYMDhmsZ");
dynConcatSz(e, &ctxPdf->mPdf, "D:", 2);
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++)
if(ctxPdf->mNbPage > 0)
{
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 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);
} /* si nb page pas connu, sera mis a la fin */
/* liste des fontes, prendre celles utilisees */
cpt = nb_obj_fixe;
cpt = ctxPdf->mNbObjFixe;
for(i = 1, nbp = 0; i <= PDFFONT_NB; i++)
{
dynField(e, &ctxPdf->mFont, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
@@ -406,6 +532,9 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
dynConcatSz(e, &ctxPdf->mPdf," /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding >> >> endobj\r\n", DYN_LGNONE);
}
}
if(nbp != nb_font)
return FALSE;
ctxPdf->mNbFont = nbp;
/* liste des images */
for(i = 1; i <= nb_img; i++)
{
@@ -422,15 +551,12 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
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
dynConcatSz(e, &ctxPdf->mPdf," /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /LZWDecode /Length ", DYN_LGNONE); // /LZWDecode remplace /ASCIIHexDecode
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 */
@@ -447,7 +573,7 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
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, Int64ToSz(e, j + ctxPdf->mNbObjFixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
@@ -458,7 +584,7 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
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, Int64ToSz(e, j + ctxPdf->mNbObjFixe + nbp, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R", DYN_LGNONE);
if(j == nb_img)
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
@@ -473,6 +599,21 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf)
{
long i, nb; /* nb xref */
if(ctxPdf->mNbPage == 0)
{
majXref(e, ctxPdf, 3);
// liste des pages
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNumPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNumPage; i++)
{
dynField(e, &ctxPdf->mInfoPage, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
}
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);
@@ -503,12 +644,45 @@ WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf)
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
{
int cr = TRUE;
int cr = TRUE, j;
/* compression = 0 : pas de compression LZW */
/* 1 : compression LZW en binaire */
setXref(e, ctxPdf);
ctxPdf->mNbObj++;
ctxPdf->mNumPage++;
if(ctxPdf->mNbPage == 0)
{
setXref(e, ctxPdf);
dynStoreNumber(e, &ctxPdf->mInfoPage, ctxPdf->mNumPage, DYN_NONE, ctxPdf->mNbObj, cFM, DYN_NONE); /* num objet declaration page (pas le contenu) */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj++, 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 <= ctxPdf->mNbFont; 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 + ctxPdf->mNbObjFixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
for(j = 1; j <= ctxPdf->mNbImg; 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 + ctxPdf->mNbObjFixe + ctxPdf->mNbFont, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R", DYN_LGNONE);
if(j == ctxPdf->mNbImg)
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> /Contents ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R >> endobj\r\n", DYN_LGNONE);
}
setXref(e, ctxPdf);
/* 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);
@@ -521,10 +695,8 @@ WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
}
else
{
// compression LZW du stream de la page
//ctxPdf->mCtxLzw.compress_do(0, (unsigned char *)ctxPdf->mPage.mPtr, ctxPdf->mPage.mLg); // verif
/* compression LZW du stream de la page */
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);
@@ -610,6 +782,33 @@ WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, lon
return cr;
}
WAPIDECL int setCab128(env * e, modContextPdf * ctxPdf, Dynamic * data, long x, long y, long h)
{
long cpt_char, code, x_orig = x, checksum = 104; /* StartB */
code = 104; /* StartB */
graphCab128(e, ctxPdf, code, &x, y, h);
for(cpt_char = 0; cpt_char < data->mLg; cpt_char++)
{
code = (long)(data->ptr[cpt_char]);
if(code > 31 && code < 127)
{
code -= 32;
graphCab128(e, ctxPdf, code, &x, y, h);
checksum += code * (cpt_char + 1);
}
/* sinon, caractere non gere en Code128 : RAF */
}
code = checksum % 103;
graphCab128(e, ctxPdf, code, &x, y, h);
code = 106; /* Stop */
graphCab128(e, ctxPdf, code, &x, y, h);
/* */
dynLet(e, &ctxPdf->mTmp3, "*", 1);
dynConcat(e, &ctxPdf->mTmp3, data);
dynConcatSz(e, &ctxPdf->mTmp3, "*", 1);
return setPdfText(e, ctxPdf, x_orig, y - h/2, x - x_orig, 80, 1, 8, RGB(0,0,0), &ctxPdf->mTmp3); // utilise la premiere fonte declaree utilisee (1), taille 8, en noir
}
WAPIDECL int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
{
int cr = TRUE;
@@ -688,6 +887,205 @@ WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
return TRUE;
}
WAPIDECL int pdfLoadImageGif(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
{
/* https://www.fileformat.info/format/gif/egff.htm */
long larg, haut, offset, ind;
long gctEntry, gct;
long lctEntry, lct, interlace;
octet * p; /* pour simplifier le code... */
/* lecture fichier */
if(!fichier)
{
return FALSE;
}
if(fichier->type != VAR_DYNAMIC)
return FALSE;
/* controle du GIF avant memorisation */
p = fichier->ptr;
if(fichier->mLg < 13)
{
return FALSE;
}
if(strncmp((char *)p, "GIF87a", 6) != 0 && strncmp((char *)p, "GIF89a", 6) != 0)
{
return FALSE; /* pas un fichier GIF */
}
if(p[fichier->mLg - 1] != '\x3B')
return FALSE; /* pas un fichier GIF */
/* les entiers sont en little-endian */
larg = (p[7] << 8) + p[6];
haut = (p[9] << 8) + p[8];
//backColor = p[11];
gct = ((p[10] & 0x80) != 0); /* presence d'une global color table */
//gctSort = ((p[10] & 0x08) != 0); /* tri de la global color table */
gctEntry = 1 << ((p[10] & 0x07) + 1); /* taille de la global color table (max 256 entrees, chacune en RGB, donc x3) */
//gctColResolution = ((p[10] & 0x70) >> 4) + 1; /* nombre de bits par couleur (max 8) */
offset = 13;
if(gct)
{
gct = offset; /* offset de la gct dans le fichier */
offset += gctEntry * 3;
}
while(offset < fichier->mLg && p[offset] == '\x21')
{
/* extension, GIF89a only */
offset++;
if(offset < fichier->mLg && p[offset] == 0xF9) /* ATTENTION : un car est signé => '\xF9' est négatif !!! */
{
/* graphics control extension */
if(fichier->mLg < offset + 7)
return FALSE;
offset += 7;
}
else if(offset < fichier->mLg && p[offset] == 0xFE) /* ATTENTION : un car est signé => '\xFE' est négatif !!! */
{
/* comment extension */
if(fichier->mLg < offset + 2)
return FALSE;
/* "sauter" tous les blocks de commentaire */
offset++;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else if(offset < fichier->mLg && p[offset] == 0xFF) /* ATTENTION : un car est signé => '\xFF' est négatif !!! */
{
/* application extension */
if(fichier->mLg < offset + 13)
return FALSE;
/* "sauter" tous les blocks data */
offset += 13;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else if(offset < fichier->mLg && p[offset] == '\x01')
{
/* plaintext extension */
if(fichier->mLg < offset + 14)
return FALSE;
/* "sauter" tous les blocks data */
offset += 14;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else
return FALSE; /* unknown extension : erreur */
}
/* ici, offset pointe sur la premier Local Image Descriptor */
if(fichier->mLg < offset + 10)
return FALSE; /* pas de partie image dans le fichier */
if(p[offset] != '\x2C')
return FALSE; /* pas de Local Image Descriptor */
/* */
larg = (p[offset + 6] << 8) + p[offset + 5];
haut = (p[offset + 8] << 8) + p[offset + 7];
lct = ((p[offset + 9] & 0x01) != 0); /* presence d'une local color table */
//lctSort = ((p[offset + 9] & 0x04) != 0); /* tri de la local color table */
interlace = ((p[offset + 9] & 0x02) != 0); /* interlace */
lctEntry = 1 << (((p[offset + 9] & 0xE0) >> 5) + 1); /* taille de la local color table (max 256 entrees, chacune en RGB, donc x3) */
offset += 10;
if(lct)
{
lct = offset; /* offset de la lct dans le fichier */
offset += lctEntry * 3;
}
/* decodage lzw de l'image a faire */
Dynamic gif, img, entre; /* gif = image decodee RGB, img = lzw decode, entre = gestion lignes entrelacees */
dynInit(e, &img, 4096);
/* mettre le decode dans img */
modContextLzw ctxLzw;
initLzw(e, &ctxLzw);
ctxLzw.inverse = TRUE; // lzw gif specifique
long type = 0; /* type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, 0 : un seul appel */
/* */
offset++; /* sauter le premier octet = lzw min code size */
while(offset < fichier->mLg && p[offset])
{
if(offset + p[offset] + 1 >= fichier->mLg)
printf("Erreur block lzw data gif\n"); /* TODO erreur de format : block plus grand que le reste du fichier */
if(p[offset + p[offset] + 1])
type = (type == 0) ? 1 : 2; /* pas le dernier bloc */
else
type = (type == 0 ? 0 : 3); /* dernier bloc */
/* */
memcopie(img.ptr, p + offset + 1, p[offset]);
img.mLg = p[offset];
/* */
getLzw(e, &img, &ctxLzw, type);
/* */
offset += p[offset] + 1;
}
/* TODO gerer erreurs (lg ko, lzw ko) */
freeLzw(e, &ctxLzw);
/* les lignes de l'image sont dans l'ordre de haut en bas, de gauche a droite
un octet par pixel donnant l'index soit dans la lct soit la gct de la couleur du pixel
si mode entrelace : les lignes sont dans l'ordre 0, +8, 4, +8, 2, +4, 1, +2
*/
//printf("avant image: larg %ld, haut %ld, offset %ld, val %d, gct %ld lct %ld\n", larg, haut, offset, p[offset], gct, lct);
//printf("img clair lg %lld, interlace:%ld\n", img.mLg, interlace);
long dx, dy, colind;
octet * q = img.ptr, * g, * h;
/* la bitmap en hexa fera une taille de larg*haut*3*2 */
dynInit(e, &gif, larg * haut * 3 * 2 + 1);
if(interlace)
{
dynInit(e, &entre, haut * 2 + 1);
short * ligent = (short *)entre.ptr, lig;
for(lig = 0; lig < (short)haut; lig += 8)
*ligent++ = lig;
for(lig = 4; lig < (short)haut; lig += 8)
*ligent++ = lig;
for(lig = 2; lig < (short)haut; lig += 4)
*ligent++ = lig;
for(lig = 1; lig < (short)haut; lig += 2)
*ligent++ = lig;
}
/* */
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
g = gif.ptr;
for(dy = 0; dy < haut; dy++)
{
if(interlace)
{
/* gerer l'entrelacement */
g = gif.ptr + ((short *)entre.ptr)[dy] * larg * 3 * 2;
}
/* */
for(dx = 0; dx < larg; dx++)
{
colind = (lct ? lct : gct) + (*q++) * 3;
/* */
h = (octet *)dynConvertCharToCharHexa(p[colind++]);
*g++ = *h++;
*g++ = *h++;
h = (octet *)dynConvertCharToCharHexa(p[colind++]);
*g++ = *h++;
*g++ = *h++;
h = (octet *)dynConvertCharToCharHexa(p[colind]);
*g++ = *h;
*g++ = *h;
}
}
dynSetLen(e, &gif, larg * haut * 3 * 2);
dynConcat(e, &ctxPdf->mImg, &gif);
dynFree(e, &gif);
if(interlace)
dynFree(e, &entre);
dynFree(e, &img);
/* verifs si d'autres images ? */
/* eventuellement a la fin, decoder les blocks possibles (GIF89a only) : comment extension, plaintext extension : remettre le bloc "while" ci dessus des extensions
enfin, verifier le dernier octet du fichier : doit etre '\x3B' (GIF terminator)
*/
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)
@@ -741,7 +1139,7 @@ WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic *
}
dynConcatSz(e, &ctxPdf->mPage, "ET\r\n", DYN_LGNONE);
//
if( ! setPdfPage(e, ctxPdf, 1)) // compression forcee, mettre un param ?
if( ! setPdfPage(e, ctxPdf, 1)) // avec compression
return FALSE;
}
return endPdf(e, ctxPdf);
+89 -62
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.
@@ -27,7 +27,9 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
enum {
RAND_STATE_COUNT = 624,
RAND_PERIOD = 397
@@ -62,7 +64,7 @@ static void randomTwist(modEtat * etat)
etat->index = 0;
}
ent32 randomGenerate(modEtat * etat)
static ent32 randomGenerate(modEtat * etat)
{
if (etat->index >= RAND_STATE_COUNT)
randomTwist(etat);
@@ -75,16 +77,20 @@ ent32 randomGenerate(modEtat * etat)
return y & 0xFFFFFFFF;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -93,111 +99,132 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
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
// - - - - - - - - - - - - - - - - - - - -
/* 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 */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
randomInit(p_etat, time(NULL));
//
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
randomInit(p_etat, time(NULL));
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == 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
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "setSeed", 7))
{
if(param1 == NULL)
/* get param in the right order */
var * paramSeedValue = getParam(e, "seedValue", 9);
if(paramSeedValue == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
else if(paramSeedValue->type != VAR_NUMBER && paramSeedValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
randomInit(p_etat, (ent32)((param1->num / NUM_FACTEUR) & 0xFFFFFFFF));
number seed;
if(var_conv_num(e, paramSeedValue, &seed))
randomInit(p_etat, (ent32)((seed / NUM_FACTEUR) & 0xFFFFFFFF));
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
/* get param in the right order */
var * paramNextRandomNumber = getParam(e, "nextRandomNumber", 16);
if(paramNextRandomNumber == NULL)
exc = EX_MODPARAM;
else
{
param1->num = (((ent64)(randomGenerate(p_etat))) * NUM_FACTEUR);
if(paramNextRandomNumber->type != VAR_NUMBER)
var_let(e, paramNextRandomNumber, &e->int_number, FALSE, FALSE);
paramNextRandomNumber->num = (((ent64)(randomGenerate(p_etat))) * NUM_FACTEUR);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+100
View File
@@ -0,0 +1,100 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "langage.h"
#include "dynamic.h"
// --- gestion protocole "raw"
typedef struct {
int state; /* etat de decodage des trames "raw" : 0 entete a lire, 1 lecture corps */
ent64s lengthToRead; /* longueur de donnees (corps) restant a lire */
Dynamic content; /* corps du message */
Dynamic line; /* variable de travail */
int error;
} modCtxRaw;
enum {
RAWSTATE_HEADERTOREAD = 0,
RAWSTATE_READINGCONTENT = 1,
/* erreurs */
RAW_ERROR_CONTENTLENGTH = 1,
/* codes retour */
RAW_REQUEST_INPROGRESS = 0,
RAW_REQUEST_COMPLETE = 1,
RAW_REQUEST_ERROR = -1
};
WAPIDECL void Init(env * e, modCtxRaw * ctx);
WAPIDECL void End(env * e, modCtxRaw * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxRaw * ctx, Dynamic * data);
WAPIDECL long MakeResponse(env * e, modCtxRaw * ctx, Dynamic * reponse);
/*
case FCGI_BEGIN_REQUEST:
// verif BEGIN_REQUEST recu : keep alive ?
mKeepAlive = (*(mDataOut.GetContentPtr() + 2) == 1);
// entre 4 Ko et 256 Ko
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) ; // erreur
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) ; // erreur
#include <netinet/tcp.h>
// Activer SO_KEEPALIVE
int yes = 1;
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
// Apres 30s d'inactivite, commencer les sondes
int idle = 30;
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
// Intervalle de 10s entre sondes
int interval = 10;
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
// 3 tentatives avant abandon
int maxpkt = 3;
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt));
// sous windows, seuls les parametres temporels se font differemment :
// Parametrage keepalive
// Activer SO_KEEPALIVE
BOOL optval = TRUE;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval));
struct tcp_keepalive keepalive;
keepalive.onoff = 1;
keepalive.keepalivetime = 30000; // 30 secondes avant 1ere sonde
keepalive.keepaliveinterval = 10000; // 10 secondes entre sondes
if (WSAIoctl(sock, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), NULL, 0, &bytesReturned, NULL, NULL) == SOCKET_ERROR)
printf("WSAIoctl failed: %d\n", WSAGetLastError());
// preco : prevoir un "heartbeat" applicatif
*/
+114
View File
@@ -0,0 +1,114 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "raw.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxRaw * ctx)
{
ctx->state = RAWSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
ctx->error = 0;
dynInit(e, &ctx->content, DYN_LGMIN);
dynInit(e, &ctx->line, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxRaw * ctx)
{
dynFree(e, &ctx->content);
dynFree(e, &ctx->line);
}
WAPIDECL long ExtractMessage(env * e, modCtxRaw * ctx, Dynamic * data)
{
if(ctx->state == RAWSTATE_HEADERTOREAD)
{
if(data->mLg < 8)
return RAW_REQUEST_INPROGRESS;
/* */
dynSubstr(e, data, &ctx->line, 0, 8, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, 8);
ctx->lengthToRead = dynToNum(e, &ctx->line, DYN_FALSE, 0);
if(ctx->line.mInternal == DYN_ERR)
{
ctx->error = RAW_ERROR_CONTENTLENGTH;
return RAW_REQUEST_ERROR;
}
ctx->error = 0;
if(ctx->lengthToRead == 0)
{
dynSetLen(e, &ctx->content, 0);
return RAW_REQUEST_COMPLETE;
}
ctx->state = RAWSTATE_READINGCONTENT;
}
if(ctx->state == RAWSTATE_READINGCONTENT)
{
// lecture corps
if(data->mLg < ctx->lengthToRead)
{
/* partiel */
dynConcat(e, &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return RAW_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees dispo */
dynConcatSz(e, &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
ctx->lengthToRead = 0;
ctx->state = RAWSTATE_HEADERTOREAD;
return RAW_REQUEST_COMPLETE;
}
}
return RAW_REQUEST_ERROR;
}
WAPIDECL long MakeResponse(env * e, modCtxRaw * ctx, Dynamic * reponse)
{
/* ajouter la longueur en debut de reponse */
long lg = reponse->mLg;
dynInsSz(e, reponse, 1, DYN_NONE, "0000000", 7, '0', DYN_NONE);
/* formater la longueur 00000000 */
dynFmtNumber(e, (ent64s)lg, &ctx->line, 'R', '0', 8);
strncpy(reponse->mPtr, ctx->line.mPtr, 8);
/* */
return OK;
}
+9
View File
@@ -393,3 +393,12 @@ WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dyna
*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);
}
WAPIDECL void GetTempDirectory(env * e, Dynamic * dir)
{
#ifdef WINLIB
dynLet(e, dir, "C:\\Temp\\", DYN_LGNONE);
#else
dynLet(e, dir, "/tmp/", 5);
#endif
}
+2
View File
@@ -40,5 +40,7 @@ WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dyn
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine);
WAPIDECL void GetTempDirectory(env * e, Dynamic * dir);
/* ********************************************** */
#endif
+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 "sock.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
/* codes a passer a la fonction setError */
enum {
WSECURESOCKET_CACERT = -6, /* genere lors de l'init, chargement certificats de confiance */
WSECURESOCKET_WANTREAD = -5,
WSECURESOCKET_WANTWRITE = -4,
WSECURESOCKET_SSLERROR = -3,
WSECURESOCKET_MEM_ERROR = -2,
WSECURESOCKET_ERROR = -1,
WSECURESOCKET_OK = 0,
};
typedef struct {
modContextSocket ctxSock;
SSL_CTX * clientSecureCtx;
SSL_CTX * serverSecureCtx;
SSL * sslServer;
SSL * sslClient;
Dynamic sslList; /* <1> = Socket ascii en MV, <2> = SSL * ent64s ascii en MV lie */
int packet; /* taille des paquets en lecture */
Dynamic lastError; /* derniere erreur : derniere opération SSL, init module */
} modContextSecureSocket;
WAPIDECL int initSecureSock(env * e, modContextSecureSocket * ctx);
WAPIDECL void freeSecureSock(env * e, modContextSecureSocket * ctx);
WAPIDECL void freeOneSecureSock(env * e, modContextSecureSocket * ctx, Socket sock);
WAPIDECL void DelSslServeur(env * e, modContextSecureSocket * ctx);
WAPIDECL long SetPemCertificate(env * e, modContextSecureSocket * ctx, Dynamic * cert, Dynamic * key);
WAPIDECL long SetCACertificate(env * e, modContextSecureSocket * ctx, Dynamic * cacert);
WAPIDECL long SecureSocketServer(env * e, modContextSecureSocket * ctx, Socket sock, long timeoutMs); /* secure socket from server accept */
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server, long timeoutMs);
WAPIDECL long ReadSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs);
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs);
+443
View File
@@ -0,0 +1,443 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 <signal.h>
#include <errno.h>
#ifdef UNIX
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#else
#include "winsock2.h"
#include "windows.h"
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "securesock.h"
typedef struct {
int error; /* dernier code erreur specifique au module */
//***
modContextSecureSocket ctxSecureSock;
} modEtat;
#define MOD_VERSION 1
enum {
EXMOD_SECURESOCK_SERVER_PORT_INVALID = 1,
EXMOD_SECURESOCK_NEW = 2,
EXMOD_SECURESOCK_SETSERVER = 3,
EXMOD_SECURESOCK_CONNECT = 4,
EXMOD_SECURESOCK_WAIT = 5,
EXMOD_SECURESOCK_ACCEPT = 6,
EXMOD_SECURESOCK_READ = 7,
EXMOD_SECURESOCK_WRITE = 8,
EXMOD_SECURESOCK_SECURESERVER = 9,
EXMOD_SECURESOCK_SECURECLIENT = 10,
EXMOD_SECURESOCK_SETCERTIFICATE = 11,
EXMOD_SECURESOCK_NOTNUM = 12,
EXMOD_NB = 12
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Port number invalid",
"New socket error",
"Listen socket on port error",
"Connect socket error",
"Waiting for socket error", // 5
"Accept socket error",
"Read socket error",
"Write socket error",
"Secure server socket error",
"Secure client socket error", // 10
"Certificate error",
"Socket expected as number"
};
/* ============================================================================================= */
#include "mod.c"
#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 */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
p_etat->error = initSecureSock(e, &p_etat->ctxSecureSock);
/* ne pas lever une exception, juste l'erreur => 1er appel est securesock&error() pour verifier que l'init (automatique) s'est bien passe (ou methode pour charger les cacert !?) */
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
freeSecureSock(e, &p_etat->ctxSecureSock);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "server", 6))
{
/* get param in the right order */
var * paramPortNumber = getParam(e, "portNumber", 10);
var * paramCertificate = getParam(e, "certificate", 11);
var * paramPrivateKey = getParam(e, "privateKey", 10);
if(paramPortNumber == NULL || paramCertificate == NULL || paramPrivateKey == NULL)
exc = EX_MODPARAM;
else if((paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC) ||
paramCertificate->type != VAR_DYNAMIC || paramPrivateKey->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* cree un point d'entree serveur securise SSL/TLS */
number port;
if( ! var_conv_num(e, paramPortNumber, &port))
exc = EX_MODPARAM;
else if(port < 1024 * NUM_FACTEUR || port > 65535 * NUM_FACTEUR)
exc = setError(p_etat, EXMOD_SECURESOCK_SERVER_PORT_INVALID); /* en dessous de 1024, necessite des autorisations speciales, non gere ici */
else
{
if(NewSocket(e, &p_etat->ctxSecureSock.ctxSock, FALSE) == WSOCKET_OK) /* uniquement socket TCP */
{
if(SocketSetServer(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.sock, (int)(port / NUM_FACTEUR), NULL) == WSOCKET_OK)
{
if(SetPemCertificate(e, &p_etat->ctxSecureSock, paramCertificate, paramPrivateKey) == WSECURESOCKET_OK)
{
exc = OK; /* un seul serveur en ecoute ! */
}
else
exc = setError(p_etat, EXMOD_SECURESOCK_SETCERTIFICATE);
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_SETSERVER);
}
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_NEW);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "connect", 7))
{
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramPortNumber = getParam(e, "portNumber", 10);
var * paramSocket = getParam(e, "socket", 6);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramHost == NULL || paramPortNumber == NULL || paramSocket == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramHost->type != VAR_DYNAMIC || (paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC) || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
/* connexion a un serveur securise SSL/TLS */
number port, timeout;
if( ! var_conv_num(e, paramPortNumber, &port) && var_conv_num(e, paramTimeout, &timeout))
exc = EX_MODPARAM;
else
{
if(NewSocket(e, &p_etat->ctxSecureSock.ctxSock, FALSE) == WSOCKET_OK) /* uniquement socket TCP */
{
if(SocketConnectToServer(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.sock, (int)(port / NUM_FACTEUR), NULL, paramHost) == WSOCKET_OK)
{
if(SecureSocketClient(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock, paramHost, timeout * 1000 / NUM_FACTEUR) == WSECURESOCKET_OK)
{
if(paramSocket->type != VAR_NUMBER)
var_let(e, paramSocket, &e->int_number, FALSE, FALSE);
paramSocket->num = p_etat->ctxSecureSock.ctxSock.sock; /* TODO tableau de connexion cliente (SSL*) */
exc = OK;
}
else
{
freeOneSecureSock(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock);
exc = setError(p_etat, EXMOD_SECURESOCK_SECURECLIENT);
}
}
else
{
/* pas de FreeSocket a faire ici */
exc = setError(p_etat, EXMOD_SECURESOCK_CONNECT);
}
}
else
{
/* pas de FreeSocket a faire ici */
exc = setError(p_etat, EXMOD_SECURESOCK_NEW);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setCACert", 9))
{
/* get param in the right order */
var * paramCert = getParam(e, "certFile", 8);
if(paramCert == NULL)
exc = EX_MODPARAM; /* erreur */
else if(paramCert->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
else
{
exc = setError(p_etat, SetCACertificate(e, &p_etat->ctxSecureSock, paramCert));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stopServer", 10))
{
/* supprime tous les ssl de type serveur et les supprime de la liste */
DelSslServeur(e, &p_etat->ctxSecureSock);
/* supprime le serveur en ecoute */
FreeSocket(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock);
p_etat->ctxSecureSock.ctxSock.servSock = INVALID_SOCKET;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stop", 4))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
if(paramSocket == NULL)
exc = EX_MODPARAM;
else if(paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* arret connexion */
number socket;
if( var_conv_num(e, paramSocket, &socket) )
freeOneSecureSock(e, &p_etat->ctxSecureSock, socket);
else
exc = setError(p_etat, EXMOD_SECURESOCK_NOTNUM);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "wait", 4))
{
/* get param in the right order */
var * paramTimeout = getParam(e, "timeout", 7);
var * paramClientSock = getParam(e, "clientSock", 10);
if(paramTimeout == NULL || paramClientSock == NULL)
exc = EX_MODPARAM;
else if(paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if( ! var_conv_num(e, paramTimeout, &timeout) )
exc = EX_MODPARAM;
else
{
if(paramClientSock->type != VAR_NUMBER)
var_let(e, paramClientSock, &e->int_number, FALSE, FALSE);
/* attend une nouvelle connexion entrante */
long cr = WaitOneSocketForRead(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock, timeout * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SECURESOCK_WAIT);
else if(cr == 0)
paramClientSock->num = NUM_MOINSUN; /* => timeout, RAS */
else
{
if(AcceptClientSocket(e, &p_etat->ctxSecureSock.ctxSock) == WSOCKET_OK)
{
if(SecureSocketServer(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock, timeout * 1000 / NUM_FACTEUR) == WSECURESOCKET_OK)
{
paramClientSock->num = p_etat->ctxSecureSock.ctxSock.sock; /* nouvelle connexion cliente securisee */
exc = OK;
}
else
{
freeOneSecureSock(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock);
exc = setError(p_etat, EXMOD_SECURESOCK_SECURESERVER);
}
}
else
exc = setError(p_etat, EXMOD_SECURESOCK_ACCEPT);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
else
{
/* lire par paquets de longueur fixe et s'arreter des que plus rien a lire, lecture par paquets de <pas> octets */
number socket, timeout;
if( var_conv_num(e, paramSocket, &socket) && var_conv_num(e, paramTimeout, &timeout) )
{
if(paramData->type != VAR_DYNAMIC)
{
var_let(e, paramData, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramData, 0);
}
/* lecture sur la connexion : lecture par paquets de longueur fixe et s'arreter des que plus rien a lire */
if(ReadSecureSocket(e, &p_etat->ctxSecureSock, socket, paramData, timeout * 1000 / NUM_FACTEUR) != WSOCKET_OK)
{
/* si erreur d'E/S, arreter tout */
freeOneSecureSock(e, &p_etat->ctxSecureSock, socket);
exc = setError(p_etat, EXMOD_SECURESOCK_READ);
}
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
else
{
number socket, timeout;
if( var_conv_num(e, paramSocket, &socket) && var_conv_num(e, paramTimeout, &timeout) )
{
/* ecriture sur la connexion : : pbm une seule socket geree ici !! */
if(WriteSecureSocket(e, &p_etat->ctxSecureSock, socket, paramData, timeout * 1000 / NUM_FACTEUR) != WSOCKET_OK)
{
/* si erreur d'E/S, arreter tout */
freeOneSecureSock(e, &p_etat->ctxSecureSock, socket);
exc = setError(p_etat, EXMOD_SECURESOCK_WRITE);
}
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+434
View File
@@ -0,0 +1,434 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "securesock.h"
#include <openssl/x509v3.h>
//#include "dynamic.h"
//#include <errno.h>
//#include <fcntl.h>
#ifdef WINLIB
#include <ws2tcpip.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/*
unix : -lssh -lcrypto -lssl -lz (dependances openssl zlib, verification avec : ldd /usr/lib/libssh.so)
sudo apt update
sudo apt install -y \
openssl libssl-dev \
zlib1g zlib1g-dev \
libssh-dev
openssl → binaire en ligne de commande
libssl-dev → headers + librairies pour compiler en C
zlib1g → runtime
zlib1g-dev → headers (zlib.h) + .so
libssh-dev → headers et libs de développement
windows : libssh.lib (et libssh compile avec msvc sinon ko)
ajouter => libssl.lib libcrypto.lib zlib.lib ws2_32.lib (car dependances openssl, zlib, socket)
git clone https://github.com/microsoft/vcpkg
cd vcpkg
bootstrap-vcpkg.bat
vcpkg install libssh:x64-windows
vcpkg install zlib:x64-windows
vcpkg install openssl:x64-windows
+ compil/link => cl main.c /I"path\to\vcpkg\installed\x64-windows\include" /link /LIBPATH:"path\to\vcpkg\installed\x64-windows\lib" libssh.lib libssl.lib libcrypto.lib zlib.lib ws2_32.lib
=> repertoire ou se trouve vcpkg (install depuis git) :
C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows
À l'exécution il faut :
libssl-*.dll
libcrypto-*.dll
dans :
même dossier que .exe ou dans le PATH
=== CERTIFICAT auto signé
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
avec windows, c'est pareil, sauf initsocket WAStartup, type SOCKET et pas int, closesocket() et il faut fournir un fichier ca (https://curl.se/ca/cacert.pem) pour la verification des certificats
https://kb.firedaemon.com/...openssl-binary-distributions : binaires openssl sous windows (3.5.6 LTS ok), ok avec libssh 0.12.x (eventuellement 0.11.x)
*/
/* ****** PRIVATE ************************ */
/*
SSL_ERROR_NONE = 0
SSL_ERROR_SSL = 1
SSL_ERROR_WANT_READ = 2
SSL_ERROR_WANT_WRITE = 3
SSL_ERROR_WANT_X509_LOOKUP = 4
SSL_ERROR_SYSCALL = 5
SSL_ERROR_ZERO_RETURN = 6
*/
static int processSSLresponse(env * e, modContextSecureSocket * ctx, SSL * ssl, int ret)
{
dynSetLen(e, &ctx->lastError, 0);
if(ret > 0)
return ret;
int ssl_err = SSL_get_error(ssl, ret);
if(ssl_err == SSL_ERROR_WANT_READ)
return WSECURESOCKET_WANTREAD;
if(ssl_err == SSL_ERROR_WANT_WRITE)
return WSECURESOCKET_WANTWRITE;
if (ssl_err == SSL_ERROR_ZERO_RETURN)
return 0; /* normalement faire SSL_Free + close socket (arrêt propre du pair) */
/* */
ERR_error_string_n(ERR_get_error(), ctx->lastError.mPtr, ctx->lastError.mLgmax);
return WSECURESOCKET_SSLERROR;
}
int verify_callback(int preverify_ok, X509_STORE_CTX * ctx) {
if (!preverify_ok) {
//int err = X509_STORE_CTX_get_error(ctx);
//int depth = X509_STORE_CTX_get_error_depth(ctx);
//printf("Échec de vérification à la profondeur %d : %s (code: %d)\n", depth, X509_verify_cert_error_string(err), err);
}
return preverify_ok;
}
static void AddSsl(env * e, modContextSecureSocket * ctx, SSL * ssl, Socket sock)
{
long pos = dynLocateSz(e, &ctx->sslList, Int64ToSz(e, (ent64s)sock, FALSE, 0), DYN_LGNONE, 1, cFM);
if(pos < 1)
{
dynInsNumber(e, &ctx->sslList, 1, 1, (ent64s)sock, cFM, cVM);
dynInsNumber(e, &ctx->sslList, 2, 1, (ent64s)ssl, cFM, cVM);
}
/* ne rien faire si deja existant */
}
static void DelSsl(env * e, modContextSecureSocket * ctx, Socket sock, int freeSsl)
{
long pos = dynLocateSz(e, &ctx->sslList, Int64ToSz(e, (ent64s)sock, FALSE, 0), DYN_LGNONE, 1, cFM);
if(pos > 0)
{
dynDel(e, &ctx->sslList, 1, pos, cFM, cVM, 1);
if(freeSsl)
SSL_free((SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM));
dynDel(e, &ctx->sslList, 2, pos, cFM, cVM, 1);
}
}
static void FreeSsl(env * e, modContextSecureSocket * ctx)
{
long nbSsl = dynDcount(e, &ctx->sslList, cVM, 1, cFM);
for(long pos = 1; pos <= nbSsl; pos++)
SSL_free((SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM));
/* SSL_shutdown(ssl) ? */
}
static SSL * GetSsl(env * e, modContextSecureSocket * ctx, Socket sock)
{
long pos = dynLocateSz(e, &ctx->sslList, Int64ToSz(e, (ent64s)sock, FALSE, 0), DYN_LGNONE, 1, cFM);
if(pos < 1)
return NULL;
else
return (SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
}
void debugSsl(env * e, modContextSecureSocket * ctx)
{
int nbSsl = dynDcount(e, &ctx->sslList, cVM, 1, cFM);
for(int pos = 1; pos <= nbSsl; pos++)
{
Socket sock = (Socket)dynFieldAsNumber(e, &ctx->sslList, 1, pos, cFM, cVM);
SSL * ssl = (SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
printf("SocketSSL[%d]=%d SSL %p / %s\n", pos, (int)sock, ssl, SSL_is_server(ssl) ? "serveur" : "client");
}
if(!nbSsl)
printf("SocketSSL empty!\n");
}
/* ****** PUBLIC ************************ */
WAPIDECL int initSecureSock(env * e, modContextSecureSocket * ctx)
{
int cr = OK;
initSock(e, &ctx->ctxSock);
/* */
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
/* */
dynInit(e, &ctx->lastError, DYN_LGMIN);
dynInit(e, &ctx->sslList, DYN_LGMIN);
/* */
ctx->packet = 64000; /* modifiable via methode a creer !? */
/* */
/* Partage un SSL_CTX si les connexions ont la même politique TLS. Crée plusieurs SSL_CTX si elles doivent avoir des politiques/configurations TLS différentes. !! */
ctx->clientSecureCtx = SSL_CTX_new(TLS_client_method());
/* */
/* Charger les autorités de confiance / appeler setCACert pour changer de cacert (test avec autosigne: appel setCACert avec le certificat serveur autosigne et le charger dans le client) */
if(SSL_CTX_set_default_verify_paths(ctx->clientSecureCtx) != 1) /* defaut linux : /etc/ssl/certs/ca-certificates.crt */
{
dynLet(e, &ctx->lastError, "error default load verify\n", DYN_LGNONE);
cr = WSECURESOCKET_CACERT;
}
/* Activer la vérification */
SSL_CTX_set_verify(ctx->clientSecureCtx, SSL_VERIFY_PEER, verify_callback); /* si dernier param = NULL, pas de verification */
/* */
ctx->serverSecureCtx = SSL_CTX_new(TLS_server_method());
/* SSL_CTX_load_verify_locations a faire sur ctxServeur si mTLS : authentification du serveur par le client (reciproque), sinon pas besoin */
/* */
return cr;
}
WAPIDECL void freeSecureSock(env * e, modContextSecureSocket * ctx)
{
FreeSsl(e, ctx); /* TODO array */
/* */
SSL_CTX_free(ctx->clientSecureCtx);
SSL_CTX_free(ctx->serverSecureCtx);
/* */
dynFree(e, &ctx->lastError);
dynFree(e, &ctx->sslList);
/* */
freeSock(e, &ctx->ctxSock);
}
WAPIDECL void freeOneSecureSock(env * e, modContextSecureSocket * ctx, Socket sock)
{
/* libere le contexte SSL et le supprime de la liste */
DelSsl(e, ctx, sock, TRUE);
/* ferme la socket et la supprime de la liste */
FreeSocket(e, &ctx->ctxSock, sock);
}
WAPIDECL void DelSslServeur(env * e, modContextSecureSocket * ctx)
{
long nbSsl = dynDcount(e, &ctx->sslList, cVM, 1, cFM);
for(long pos = nbSsl; pos > 0; pos--)
{
/* partir de la fin pour que les dynDel fonctionnent correctement */
SSL * ssl = (SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
if(SSL_is_server(ssl))
{
SSL_free(ssl);
Socket sock = (Socket)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
FreeSocket(e, &ctx->ctxSock, sock);
/* */
dynDel(e, &ctx->sslList, 1, pos, cFM, cVM, 1);
dynDel(e, &ctx->sslList, 2, pos, cFM, cVM, 1);
}
}
}
WAPIDECL long SetCACertificate(env * e, modContextSecureSocket * ctx, Dynamic * cacert)
{
if (!SSL_CTX_load_verify_locations(ctx->clientSecureCtx, cacert->mPtr, NULL))
return WSECURESOCKET_CACERT;
else
return WSECURESOCKET_OK;
}
WAPIDECL long SetPemCertificate(env * e, modContextSecureSocket * ctx, Dynamic * cert, Dynamic * key)
{
if(SSL_CTX_use_certificate_file(ctx->serverSecureCtx, cert->mPtr, SSL_FILETYPE_PEM) <= 0)
return WSECURESOCKET_ERROR;
if(SSL_CTX_use_PrivateKey_file(ctx->serverSecureCtx, key->mPtr, SSL_FILETYPE_PEM) <= 0)
return WSECURESOCKET_ERROR;
return WSECURESOCKET_OK;
}
WAPIDECL long SecureSocketServer(env * e, modContextSecureSocket * ctx, Socket sock, long timeoutMs)
{
/* secure socket from server accept */
SetBlocking(sock, WSOCKET_NONBLOCKING);
ctx->sslServer = SSL_new(ctx->serverSecureCtx);
SSL_set_fd(ctx->sslServer, sock);
AddSsl(e, ctx, ctx->sslServer, sock); /* TODO array */
/* */
int ret;
for(;;)
{
if((ret = processSSLresponse(e, ctx, ctx->sslServer, SSL_accept(ctx->sslServer))) < 0)
{
if(ret == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, sock, timeoutMs);
if(cr > 0)
continue; /* donnees ok */
}
if(ret == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, sock, timeoutMs);
if(cr > 0)
continue; /* donnees ok */
}
return WSECURESOCKET_ERROR;
}
else
break; /* ok */
}
return WSECURESOCKET_OK;
}
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server, long timeoutMs)
{
int ret;
/* secure socket connected to a server */
SetBlocking(sock, WSOCKET_NONBLOCKING);
ctx->sslClient = SSL_new(ctx->clientSecureCtx);
SSL_set_fd(ctx->sslClient, sock);
AddSsl(e, ctx, ctx->sslClient, sock); /* TODO array */
SSL_set_tlsext_host_name(ctx->sslClient, server->mPtr); /* necessaire sur google.fr par exemple, a garder ? */
/* */
for(;;) // TODO mettre un timeout global !?
{
if((ret = processSSLresponse(e, ctx, ctx->sslClient, SSL_connect(ctx->sslClient))) < 0)
{
if(ret == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, sock, timeoutMs);
if(cr >= 0)
continue; /* donnees ok */
}
if(ret == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, sock, timeoutMs);
if(cr >= 0)
continue; /* donnees ok */
}
return WSECURESOCKET_ERROR;
}
else
break; /* ok */
}
/* */
if(SSL_get_verify_result(ctx->sslClient) != X509_V_OK)
return WSECURESOCKET_ERROR;
X509 * cert;
if( ! (cert = SSL_get_peer_certificate(ctx->sslClient)) )
return WSECURESOCKET_ERROR;
int cr = X509_check_host(cert, server->mPtr, 0, 0, NULL);
X509_free(cert);
if(cr != 1)
return WSECURESOCKET_ERROR;
/* */
return WSECURESOCKET_OK;
}
WAPIDECL long ReadSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs)
{
SSL * ssl;
if(!(ssl = GetSsl(e, ctx, sock))) return WSECURESOCKET_ERROR; /* TODO array */
/* */
int packetLg = ctx->packet, nbRead;
/* */
for(;;)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr < 0)
return WSECURESOCKET_ERROR;
else if(cr == 0)
return WSECURESOCKET_OK; /* => timeout, RAS en lecture */
/* prepare la prochaine lecture */
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
return WSECURESOCKET_MEM_ERROR; // erreur memoire
for(;;)
{
if((nbRead = processSSLresponse(e, ctx, ssl, SSL_read(ssl, data->mPtr + data->mLg, packetLg))) < 0)
{
if(nbRead == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr <= 0)
return WSECURESOCKET_ERROR;
continue;
}
if(nbRead == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr <= 0)
return WSECURESOCKET_ERROR;
continue;
}
return WSECURESOCKET_ERROR;
}
dynSetLen(e, data, data->mLg + nbRead);
if(nbRead < packetLg)
return WSECURESOCKET_OK;
/* si lg maxi lue, sans doute d'autres donnees a lire : continuer (ou faire systematiquement ?) */
break;
}
}
}
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs)
{
SSL * ssl;
if(!(ssl = GetSsl(e, ctx, sock))) return WSECURESOCKET_ERROR; /* TODO array */
/* */
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr <= 0)
return WSECURESOCKET_ERROR; /* timeout = error */
/* */
ent64s dejaLu = 0;
int nbWrite;
for(;;)
{
if((nbWrite = processSSLresponse(e, ctx, ssl, SSL_write(ssl, data->mPtr + dejaLu, data->mLg - dejaLu))) < 0)
{
if(nbWrite == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr > 0)
continue;
}
if(nbWrite == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr > 0)
continue;
}
return WSECURESOCKET_ERROR;
}
else
{
if(nbWrite >= data->mLg - dejaLu)
break; /* data ok */
/* tout n'a pas ete ecrit : continuer */
dejaLu += nbWrite;
}
}
return WSECURESOCKET_OK;
}
-3
View File
@@ -68,6 +68,3 @@ 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);
+111 -72
View File
@@ -27,23 +27,34 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
/* ============================================================================================= */
#include "shm.h"
typedef struct {
int error; // dernier code erreur specifique au module
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;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_PROCESSNAME_TOOLONG = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Name of process too long (from 1 to 23)"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -52,123 +63,151 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
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
// - - - - - - - - - - - - - - - - - - - -
/* 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 */
/* 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
if(p_etat == NULL)
{
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);
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** 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);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeShm(e, &p_etat->cs);
//*** FIN du code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
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
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(!param1)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramContent = getParam(e, "content", 7);
if(paramContent == NULL)
exc = EX_MODPARAM;
else
{
p_etat->cs.message = param1;
exc = setError(p_etat, readShm(e, &p_etat->cs));
// param1 vide si rien a lire
if(paramContent->type != VAR_DYNAMIC)
var_let(e, paramContent, &e->int_dynamic, FALSE, FALSE);
p_etat->cs.message = paramContent;
exc = setError(p_etat, readShm(e, &p_etat->cs)); // paramContent renvoye a vide si rien a lire
}
}
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
if(!param1 || !param2)
/* get param in the right order */
var * paramTextMessage = getParam(e, "textMessage", 11);
var * paramProcessName = getParam(e, "processName", 11);
if(paramTextMessage == NULL || paramProcessName == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramTextMessage->type != VAR_DYNAMIC || paramProcessName->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));
if(paramProcessName->mLg > 0 && paramProcessName->mLg < 24)
{
strncpy(p_etat->cs.desti, paramProcessName->mPtr, paramProcessName->mLg);
p_etat->cs.message = paramTextMessage;
exc = setError(p_etat, writeShm(e, &p_etat->cs));
}
else
exc = setError(p_etat, EXMOD_PROCESSNAME_TOOLONG);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
/* **************************************************************************************************** */
+1 -102
View File
@@ -261,108 +261,7 @@ WAPIDECL long writeShm(env * e, modContextShm * ctx)
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;
}
/* utilite ? */
#ifndef WINLIB
WAPIDECL int OpenLock(env * e, const char * name)
{
+39 -17
View File
@@ -25,54 +25,76 @@
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#ifndef WINLIB
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#include <unistd.h>
typedef int Socket;
typedef struct pollfd * wPoll;
#define INVALID_SOCKET -1
#else
#include "winsock2.h" // link avec ws2_32.lib
#include <afunix.h>
#include <windows.h>
typedef SOCKET Socket;
typedef LPWSAPOLLFD wPoll;
typedef Socket * 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
WSOCKET_END_CONNECT = -3,
WSOCKET_MEM_ERROR = -2,
WSOCKET_ERROR = -1,
WSOCKET_OK = 0,
WSOCKET_LISTEN_MAX = 10,
/* */
WSOCKET_BLOCKING = 0,
WSOCKET_NONBLOCKING = 1
};
typedef struct {
var * listSocket; // contient le tableau de pollfd/WSAPOLLFD encapsule dans un dynamic
Dynamic listSocket; // contient le tableau de pollfd/Socket encapsule dans un dynamic
Dynamic localSocket; // chemin de la socket unix locale, vide si socket TCP
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 ?) */
int posAddSocket; // endroit ou l'ajout a ete fait dans listSocket
wPoll poll; // pointeur vers le tableau de pollfd/Socket
Socket servSock;
Socket sock; // socket en cours (tmp)
int packet; // taille des paquets lus un par un
int err; // derniere erreur socket (errno ou WSAGetLastError())
#ifdef WINLIB
fd_set fds;
struct timeval tv;
#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 SetBlocking(Socket sock, int blocking);
WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx, int local);
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port, var * localPath);
WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx);
WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * localPath, var * server);
WAPIDECL long 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 long WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL long WaitSocketForWrite(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL long WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs);
WAPIDECL long WaitOneSocketForWrite(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 int SocketWouldBlock();
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data, long timeoutMs);
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data);
WAPIDECL long SendSocket(env * e, modContextSocket * ctx, Socket sock, Socket socketToSend, number pid);
WAPIDECL long ReceiveSocket(env * e, modContextSocket * ctx, Socket sock, Socket * socketReceived);
+421 -374
View File
@@ -25,44 +25,73 @@
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "rep.h"
#include <signal.h>
#include <errno.h>
#ifdef UNIX
#ifdef WINLIB
#include "winsock2.h"
#include "windows.h"
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#else
#include "winsock2.h"
#include "windows.h"
#include <sys/utsname.h>
#endif
#include "langage.h"
#include "dynamic.h"
/* ============================================================================================= */
#include "sock.h"
typedef struct {
int error; /* dernier code erreur specifique au module */
//***
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
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextSocket ctxSock;
} modEtat;
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_SOCK_SERVER_PORT_NUM = 1,
EXMOD_SOCK_SERVER_PORT_INVALID = 2,
EXMOD_SOCK_NEW = 3,
EXMOD_SOCK_SETSERVER = 4,
EXMOD_SOCK_CONNECT = 5,
EXMOD_SOCK_WAIT = 6,
EXMOD_SOCK_ACCEPT = 7,
EXMOD_SOCK_READ = 8,
EXMOD_SOCK_WRITE = 9,
EXMOD_SOCK_NOTNUM = 10,
EXMOD_SOCK_GETHOST = 11,
EXMOD_SOCK_GETNAME = 12,
EXMOD_NB = 12
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Port number expected as number",
"Port number invalid",
"New socket error",
"Listen socket on port error",
"Connect socket error", // 5
"Waiting for socket error",
"Accept socket error",
"Read socket error",
"Write socket error",
"Socket expected as number", // 10
"Get host address error",
"Get host name error"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -71,446 +100,464 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
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
// fonction createServer, arret
// - - - - - - - - - - - - - - - - - - - -
/* 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 */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
initSock(e, &p_etat->cs);
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initSock(e, &p_etat->ctxSock);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
freeSock(e, &p_etat->cs);
//***
//*** code specifique ici
freeSock(e, &p_etat->ctxSock);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
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
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "server", 6))
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
{
exc = EX_MODETAT;
return exc;
}
// param<1> = numero de port ; TODO : mettre une VAR_NUMBER ??
long port = dynToNum(e, param1, 0, 5);
if(param1->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
}
if(port < 1024 || port > 65535)
{
exc = setError(p_etat, 1);
return exc;
}
//
struct sockaddr_in addr;
struct linger l_s; /* Structure pour setsockopt */
int sockopt, buf = 64000; /* taille buffer send/rec = 64 ko environ */
int arg = 1; /* pour ioctl */
// cree une socket serveur prete a ecouter
/* mise en place de la socket serveur d'ecoute */
if((p_etat->mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */
#endif
/* */
#ifdef UNIX
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
#endif
/* */
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
// 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)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if(bind(p_etat->mSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* get param in the right order */
var * paramPortNumber = getParam(e, "portNumber", 10);
/* TODO socket unix locale (pas en mode secure) */
if(paramPortNumber == NULL)
exc = EX_MODPARAM;
else if(paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
if(listen(p_etat->mSocket, 10) < 0)
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
{
/* cree un point d'entree serveur */
number port;
if( ! var_conv_num(e, paramPortNumber, &port))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM);
else if(port < 1024 * NUM_FACTEUR || port > 65535 * NUM_FACTEUR)
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_INVALID); /* en dessous de 1024, necessite des autorisations speciales, non gere ici */
else
{
/* socket non bloquante (autre possibilite) */
//fcntl(sock, F_GETFL, &sockopt);
//fcntl(sock, F_SETFL, sockopt|O_NONBLOCK);
/* OK */
p_etat->mServeur = 0;
#ifdef UNIX
sigemptyset(&p_etat->mOldBlockSig);
sigfillset(&p_etat->mBlockSig);
#endif
if(NewSocket(e, &p_etat->ctxSock, FALSE) == WSOCKET_OK)
{
if(SocketSetServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), NULL) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SOCK_SETSERVER);
}
else
exc = setError(p_etat, EXMOD_SOCK_NEW);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "connect", 7))
{
char ** tParam;
/* connexion a un serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(dynDcount(e, param1, cFM, DYN_NONE, DYN_NONE) < 2)
exc = EX_MODPARAM; /* erreur */
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramPortNumber = getParam(e, "portNumber", 10);
var * paramSocket = getParam(e, "socket", 6);
/* socket unix locale (pas en mode secure) */
if(paramHost == NULL || paramPortNumber == NULL || paramSocket == NULL)
exc = EX_MODPARAM;
else if(paramHost->type != VAR_DYNAMIC || (paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
// param<1> = host (nom ou ip)
// param<2> = port
// decouper en 2 chaines Comm
tParam = dynToTabPtr(e, param1, cFM);
if(tParam == NULL)
exc = EX_MODPARAM; /* erreur */
}
if(exc != OK)
return exc;
long port = atoi(tParam[1]);
if(param1->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
}
if(port < 1 || port > 65535)
{
exc = setError(p_etat, 1);
return exc;
}
//
struct hostent * serv;
struct sockaddr_in addr;
struct linger l_s; /* Structure pour setsockopt */
int sockopt, buf = 64000; /* taille buffer send/rec = 64 ko environ */
int arg = 1; /* pour ioctl */
// cree une socket serveur prete a ecouter
/* mise en place de la socket serveur d'ecoute */
if((p_etat->mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */
#endif
/* */
#ifdef UNIX
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
#endif
/* */
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
// 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)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
/* pour l'adresse, soit host soit ip */
if((serv = gethostbyname(tParam[0])) == NULL)
; /* erreur */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(serv->h_addr);
if (connect(p_etat->mSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
; /* erreur : lire errno : EISCONN (deja:ok), EINPROGRESS EALREADY (en cours:ressayer), sinon erreur */
else
{
p_etat->mServeur = 2; /* client */
#ifdef UNIX
sigemptyset(&p_etat->mOldBlockSig);
sigfillset(&p_etat->mBlockSig);
#endif
/* connexion a un serveur */
number port;
if( ! var_conv_num(e, paramPortNumber, &port))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM);
else
{
if(NewSocket(e, &p_etat->ctxSock, FALSE) == WSOCKET_OK)
{
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), NULL, paramHost) == WSOCKET_OK)
{
if(paramSocket->type != VAR_NUMBER)
var_let(e, paramSocket, &e->int_number, FALSE, FALSE);
paramSocket->num = p_etat->ctxSock.sock; /* (sock * NUM_FACTEUR) ? */
}
else
exc = setError(p_etat, EXMOD_SOCK_CONNECT);
}
else
exc = setError(p_etat, EXMOD_SOCK_NEW);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "arret", 5))
else if(modFnIs(e, "stopServer", 10))
{
/* arret connexion cliente ou serveur */
if(p_etat != NULL)
/* arret serveur */
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.servSock);
p_etat->ctxSock.servSock = INVALID_SOCKET;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stop", 4))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
if(paramSocket == NULL)
exc = EX_MODPARAM;
else if(paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
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;
/* arret connexion */
number socket;
if( var_conv_num(e, paramSocket, &socket) )
FreeSocket(e, &p_etat->ctxSock, socket);
else
exc = setError(p_etat, EXMOD_SOCK_NOTNUM);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "attente", 7))
else if(modFnIs(e, "wait", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
/* get param in the right order */
var * paramTimeout = getParam(e, "timeout", 7);
var * paramClientSock = getParam(e, "clientSock", 10);
if(paramTimeout == NULL || paramClientSock == NULL)
exc = EX_MODPARAM;
else if(paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
fd_set masque;
struct timeval delai;
long cr;
// attend une activite sur la socket, timeOut en 1/10 de 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);
//
if(p_etat->mServeur == 0)
{
// pour que le select() fonctionne a chaque fois (a chaque time-out), il faut remettre à jour
// les variables "delai" et "masque fd" ; il faut aussi imperativement
// bloquer les signaux !! la socket peut etre bloquante (mais il vaut mieux la mettre non bloquante)
#ifdef UNIX
sigprocmask(SIG_SETMASK, &p_etat->mBlockSig, &p_etat->mOldBlockSig);
#endif
cr = select(p_etat->mSocket + 1, &masque, NULL, NULL, &delai);
#ifdef UNIX
sigprocmask(SIG_SETMASK, &p_etat->mOldBlockSig, NULL);
#endif
}
number timeout;
if( ! var_conv_num(e, paramTimeout, &timeout) )
exc = EX_MODPARAM;
else
{
while((cr = select(p_etat->mSocket + 1, &masque, NULL, NULL, &delai)) < 0 && errno == EINTR) errno = 0;
if(cr > 0)
cr = FD_ISSET(p_etat->mSocket, &masque);
if(paramClientSock->type != VAR_NUMBER)
var_let(e, paramClientSock, &e->int_number, FALSE, FALSE);
// attend une activite sur la socket serveur et si oui cree une nouvelle socket, timeout en secondes
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, p_etat->ctxSock.servSock, timeout * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
paramClientSock->num = NUM_MOINSUN; /* => timeout, RAS */
else
{
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
paramClientSock->num = p_etat->ctxSock.sock;
}
else
exc = setError(p_etat, EXMOD_SOCK_ACCEPT);
}
}
if(cr > 0)
param1->num = NUM_UN; /* ok pour lire */
else
param1->num = NUM_ZERO; /* pas de donnees */
// si cr > 0 : ok pour continuer et lire la socket
}
}
/* ----------------------------------------------------------------------------------------------- */
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(param1 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_DYNAMIC)
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
else
{
// lire par paquets de longueur fixe et s'arrêter dès que plus rien à lire
// lecture par paquets de <pas> octets
#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, param1, 0);
do
number socket, timeout;
if( var_conv_num(e, paramSocket, &socket) && var_conv_num(e, paramTimeout, &timeout) )
{
if(!dynCtrl(e, param1, param1->mLg + pas, 1)) /* avec recopie */
if(paramData->type != VAR_DYNAMIC)
{
exc = setError(p_etat, 1);
break;
var_let(e, paramData, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramData, 0);
}
would_block = 0;
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
Sleep(10);
#endif
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, param1, param1->mLg + nblu);
/* */
} while (nblu > 0);
/* lecture sur la connexion : lecture par paquets de longueur fixe et s'arreter des que plus rien a lire
lecture par paquets de <pas> octets */
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, socket, timeout * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
dynSetLen(e, paramData, 0); /* => timeout, RAS */
else
{
/* socket a recu des donnees */
if(ReadSocket(e, &p_etat->ctxSock, socket, paramData, timeout * 1000 / NUM_FACTEUR) != WSOCKET_OK)
/* traiter le cas WSOCKET_END_CONNECT : erreur ? (fin cnx) */
exc = setError(p_etat, EXMOD_SOCK_READ);
}
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
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(param1 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
if(paramSocket == NULL || paramData == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_DYNAMIC)
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
else
{
lg = param1->mLg;
while(lg > 0)
number socket;
if( var_conv_num(e, paramSocket, &socket) )
{
would_block = 0;
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 ?) */
#else
Sleep(10);
#endif
if(nb <= 0)
/* ecriture sur la connexion */
if(WriteSocket(e, &p_etat->ctxSock, socket, paramData) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SOCK_WRITE);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getHostname", 11))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramIp = getParam(e, "ip", 2);
if(paramName == NULL || paramIp == NULL)
exc = EX_MODPARAM;
else
{
if(paramName->type != VAR_DYNAMIC)
var_let(e, paramName, &e->int_dynamic, FALSE, FALSE);
if(paramIp->type != VAR_DYNAMIC)
var_let(e, paramIp, &e->int_dynamic, FALSE, FALSE);
#ifdef WINLIB
long size = paramName->mLgmax;
if (!GetComputerNameA(paramName->mPtr, &size))
exc = setError(p_etat, EXMOD_SOCK_GETNAME);
else
{
dynSetLen(e, paramName, strlen(paramName->mPtr));
if (gethostname(paramIp->mPtr, paramIp->mLgmax) == SOCKET_ERROR)
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
else
{
exc = setError(p_etat, 2);
break;
struct hostent * host_entry;
host_entry = gethostbyname(paramIp->mPtr);
dynSetLen(e, paramIp, 0); // paramIp var tmp ici
if (host_entry == NULL)
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
else if(host_entry->h_addr_list == NULL)
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
else
{
dynLet(e, paramIp, inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]), DYN_LGNONE);
}
}
lg -= nb;
if(lg > 0)
pos += nb; /* ecriture en plusieurs fois */
}
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
{
if(dynCtrl(e, paramName, (lg = strlen(name.nodename)), DYN_FALSE) == DYN_OK)
{
dynLet(e, paramName, name.nodename, lg);
// lecture ip
struct hostent * host = gethostbyname(paramName->mPtr);
if(host)
dynLet(e, paramIp, inet_ntoa(*(struct in_addr *)host->h_addr_list[0]), DYN_LGNONE);
else
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
}
else
exc = EX_MEM;
}
else
exc = setError(p_etat, EXMOD_SOCK_GETNAME);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "export", 6))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramPid = getParam(e, "pid", 3);
/* envoi d'une socket a un autre process via son pid, par socket unix locale (non secu) */
if(paramSocket == NULL || paramPid == NULL)
exc = EX_MODPARAM;
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || (paramPid->type != VAR_NUMBER && paramPid->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
number socket, pid;
if( ! var_conv_num(e, paramSocket, &socket) || ! var_conv_num(e, paramPid, &pid))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM); // TODO
else
{
if(NewSocket(e, &p_etat->ctxSock, TRUE) == WSOCKET_OK)
{
GetTempDirectory(e, &e->tmp_dynamic);
dynConcatSz(e, &e->tmp_dynamic, "wsocket_", 8);
dynConcatNumber(e, &e->tmp_dynamic, pid);
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, 0, &e->tmp_dynamic, NULL) == WSOCKET_OK)
{
if(SendSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, socket, pid) == OK)
{
if(ReadSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, &e->tmp_dynamic, 1000) == WSOCKET_OK) /* delai 1 sec. */
{
/* verifier si les donnes lues sont egales a "OK" */
/* socket bien recue par l'autre process : fermer celle ici */
FreeSocket(e, &p_etat->ctxSock, socket);
}
else
exc = setError(p_etat, EXMOD_SOCK_READ); // TODO
}
else
exc = setError(p_etat, EXMOD_SOCK_READ); // TODO
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock);
}
else
exc = setError(p_etat, EXMOD_SOCK_CONNECT); // TODO
}
else
exc = setError(p_etat, EXMOD_SOCK_NEW); // TODO
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "accept", 6))
else if(modFnIs(e, "import", 6))
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
/* recuperation d'une socket depuis un autre process, par socket unix locale (non secu) */
if(paramSocket == NULL)
exc = EX_MODPARAM;
else
{
struct sockaddr_in addr_cnx;
unsigned int size_addr_cnx = sizeof(addr_cnx);
int sock;
if((sock = accept(p_etat->mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
param1->num = sock * NUM_FACTEUR; /* nouvelle requete entrante : renvoie num socket */
if(paramSocket->type != VAR_NUMBER)
var_let(e, paramSocket, &e->int_number, FALSE, FALSE);
paramSocket->num = NUM_MOINSUN;
/* */
if(NewSocket(e, &p_etat->ctxSock, TRUE) == WSOCKET_OK)
{
GetTempDirectory(e, &e->tmp_dynamic);
dynConcatSz(e, &e->tmp_dynamic, "wsocket_", 8);
dynConcatNumber(e, &e->tmp_dynamic, getpid());
if(SocketSetServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, 0, &e->tmp_dynamic) == WSOCKET_OK)
{
// couper ici et faire 2 fn : une qui init la socket unix locale, et une qui ecoute et lit une socket
// attend une activite sur la socket serveur et si oui cree une nouvelle socket, timeout 1 seconde en ms
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, p_etat->ctxSock.servSock, 1000);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
; /* => timeout, RAS */
else
{
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
Socket socket;
if(ReceiveSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, &socket) == OK)
{
dynLet(e, &e->tmp_dynamic, "OK", 2);
if(WriteSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, &e->tmp_dynamic) == WSOCKET_OK)
{
/* socket bien recue de l'autre process */
paramSocket->num = socket;
}
else
exc = setError(p_etat, EXMOD_SOCK_WRITE); // TODO
}
else
exc = setError(p_etat, EXMOD_SOCK_READ); // TODO
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock);
}
else
exc = setError(p_etat, EXMOD_SOCK_ACCEPT);
}
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.servSock); // idem 'stopserver', a separer
}
else
exc = setError(p_etat, EXMOD_SOCK_CONNECT); // TODO
}
else
param1->num = NUM_ZERO; /* pas de nouvelle connexion entrante finalement */
exc = setError(p_etat, EXMOD_SOCK_NEW); // TODO
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+651 -196
View File
@@ -25,6 +25,8 @@
#include "dynamic.h"
#include <errno.h>
#include <fcntl.h>
#ifdef WINLIB
#include <ws2tcpip.h>
#endif
@@ -41,11 +43,39 @@
/* ---------------------------------------------------- */
/* ****** PRIVATE ************************ */
static void DeleteLocalSocketFile(env * e, modContextSocket * ctx)
{
if(ctx->localSocket.mLg > 0)
#ifndef WINLIB
unlink(ctx->localSocket.mPtr);
#else
DeleteFileA(ctx->localSocket.mPtr);
#endif
dynSetLen(e, &ctx->localSocket, 0);
}
static int SetCloexec(Socket fd)
{
#ifndef WINLIB
int ret = fcntl(fd, F_GETFD);
if(ret != -1)
ret = fcntl(fd, F_SETFD, ret | FD_CLOEXEC);
return (ret == -1); /* TRUE si erreur */
#else
return 0;
#endif
}
/* ****** PUBLIC ************************ */
WAPIDECL void initSock(env * e, modContextSocket * ctx)
{
dynSetLen(e, ctx->listSocket, 0); // raz liste sockets
dynInit(e, &ctx->listSocket, DYN_LGMIN);
dynSetLen(e, &ctx->listSocket, 0); // raz liste sockets
dynInit(e, &ctx->localSocket, DYN_LGMIN);
ctx->servSock = INVALID_SOCKET;
ctx->sock = INVALID_SOCKET;
ctx->packet = 16000; /* parametrable par une fonction ? */
ctx->nbSocket = 0;
//
#ifdef WINLIB
WSADATA wsa;
@@ -55,14 +85,41 @@ WAPIDECL void initSock(env * e, modContextSocket * ctx)
WAPIDECL void freeSock(env * e, modContextSocket * ctx)
{
// TODO fermer les sockets ouvertes
/* fermer les sockets ouvertes */
DeleteLocalSocketFile(e, ctx);
/* */
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
{
#ifndef WINLIB
shutdown(ctx->poll[cpt].fd, SHUT_RDWR);
close(ctx->poll[cpt].fd);
#else
shutdown(ctx->poll[cpt], SD_BOTH);
closesocket(ctx->poll[cpt]);
#endif
}
dynFree(e, &ctx->listSocket);
dynFree(e, &ctx->localSocket);
#ifdef WINLIB
WSACleanup();
#endif
}
WAPIDECL Socket NewSocket()
WAPIDECL void SetBlocking(Socket sock, int blocking)
{
#ifndef WINLIB
int sockopt = blocking; // 1 = non-bloquant, 0 = bloquant
ioctl(sock, FIONBIO, &sockopt);
#else
u_long block_mode = blocking; // 1 = non-bloquant, 0 = bloquant
ioctlsocket(sock, FIONBIO, &block_mode);
#endif
}
WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx, int local)
{
/* local = 1: socket unix, sinon socket TCP */
#ifdef WINLIB
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
@@ -70,213 +127,584 @@ WAPIDECL Socket NewSocket()
int iOptLen = sizeof(int);
u_long block_mode = 1; // 1 = non-bloquant, 0 = bloquant
#else
int sockopt = 1;
int sockopt = 1; // 1 = non-bloquant, 0 = bloquant
#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
if(local)
{
/* socket "Unix" (local a une machine) */
#ifndef WINLIB
close(sock);
if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
#else
closesocket(sock);
if((sock = WSASocket(AF_UNIX, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT)) == INVALID_SOCKET)
#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)
{
ctx->err = GetSocketError();
return WSOCKET_ERROR;
}
}
else
{
/* socket TCP */
#ifndef WINLIB
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
#else
if((sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT)) == INVALID_SOCKET)
#endif
{
ctx->err = GetSocketError();
return WSOCKET_ERROR;
}
}
/* */
//#ifndef WINLIB
//ioctl(sock, FIONBIO, &sockopt); /* socket non bloquant (sys/ioctl.h) */
//#else
//ioctlsocket(sock, FIONBIO, &block_mode);
//#endif
SetCloexec(sock); /* sous Windows, le flag WSA_FLAG_NO_HANDLE_INHERIT fait la meme chose lors du CreateProcess */
/* */
SetBlocking(sock, WSOCKET_NONBLOCKING);
/* */
if(!local) /* options inutiles en mode socket unix locale */
{
/* 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
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
return WSOCKET_ERROR;
}
addr.sin_addr.s_addr = ((struct in_addr *)(serv->h_addr))->s_addr;
/* 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)))
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return WSOCKET_ERROR;
}
}
/* autres options ?
int flag = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); // demande à TCP d'envoyer les données sans attendre leur regroupement, afin de privilégier la faible latence plutôt que l'efficacité du trafic réseau.
//
int buf = 64000; // de 4 ko a 256 Ko, mais impact tres limite => prevoir plutot un heartbeat applicatif
if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) ; // erreur
if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) ;
// keep alive ?
#ifndef WINLIB
// Activer SO_KEEPALIVE
int yes = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes))) ; // erreur
// Apres 30s d'inactivite, commencer les sondes
int idle = 30;
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) ;
// Intervalle de 10s entre sondes
int interval = 10;
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval))) ;
// 3 tentatives avant abandon
int maxpkt = 3;
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt))) ;
#else
// sous windows, seuls les parametres temporels se font differemment :
BOOL optval = TRUE;
if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval))) ;
struct tcp_keepalive keepalive;
keepalive.onoff = 1;
keepalive.keepalivetime = 30000; // 30 secondes avant 1ere sonde
keepalive.keepaliveinterval = 10000; // 10 secondes entre sondes
if(WSAIoctl(sock, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), NULL, 0, &bytesReturned, NULL, NULL) == SOCKET_ERROR) ;
#endif
*/
ctx->sock = sock;
return WSOCKET_OK;
}
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port, var * localPath)
{
struct sockaddr * sa;
int sofsa;
/* */
dynSetLen(e, &ctx->localSocket, 0);
if(localPath)
{
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
dynSetAs(e, &ctx->localSocket, localPath);
/* localPath doit contenir le chemin complet d'un "fichier" unique pour la socket locale (exemple: /tmp/wsock_1234.sock et C:\\Temp\\wsock_1234.sock) */
if(ctx->localSocket.mLg >= sizeof(addr.sun_path))
{
dynSetLen(e, &ctx->localSocket, 0);
return WSOCKET_ERROR;
}
strcpy(addr.sun_path, ctx->localSocket.mPtr);
/* Supprimer l'ancien fichier de socket s'il existe, sinon le prochain bind echouera */
#ifndef WINLIB
unlink(addr.sun_path);
#else
DeleteFileA(addr.sun_path);
#endif
sa = (struct sockaddr *)&addr;
sofsa = sizeof(addr);
}
else
{
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);
sa = (struct sockaddr *)&addr;
sofsa = sizeof(addr);
}
#ifndef WINLIB
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
if(bind(sock, sa, sofsa) < 0)
#else
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == EXMOD_SOCKET_ERROR)
if(bind(sock, sa, sofsa) == SOCKET_ERROR)
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
DeleteLocalSocketFile(e, ctx);
return WSOCKET_ERROR;
}
#ifndef WINLIB
if(listen(sock, WSOCKET_LISTEN_MAX) < 0)
#else
if(listen(sock, WSOCKET_LISTEN_MAX) == SOCKET_ERROR)
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
DeleteLocalSocketFile(e, ctx);
return WSOCKET_ERROR;
}
if(AddSocket(e, ctx, sock) == WSOCKET_OK)
{
ctx->servSock = sock;
return WSOCKET_OK;
}
else
{
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR; /* erreur (TODO plusieurs essais avant erreur ?) */
DeleteLocalSocketFile(e, ctx);
return WSOCKET_ERROR;
}
if(AddSocket(e, ctx, sock))
return EXMOD_SOCKET_OK;
else
return EXMOD_SOCKET_ERROR;
}
WAPIDECL int AddSocket(env * e, modContextSocket * ctx, Socket sock)
WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx)
{
// 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;
struct sockaddr_in addr_cnx;
ctx->sock = 0;
#ifndef WINLIB
unsigned int size_addr_cnx = sizeof(addr_cnx);
if((ctx->sock = accept(ctx->servSock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
#else
int size_addr_cnx = sizeof(addr_cnx);
if((ctx->sock = accept(ctx->servSock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) != INVALID_SOCKET)
#endif
{
if(AddSocket(e, ctx, ctx->sock) == WSOCKET_OK)
return WSOCKET_OK;
else
{
#ifdef WINLIB
closesocket(ctx->sock);
#else
close(ctx->sock);
#endif
return WSOCKET_ERROR;
}
}
else
{
ctx->err = GetSocketError();
return WSOCKET_ERROR;
}
}
WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * localPath, var * server)
{
struct sockaddr * sa;
int sofsa;
/* utilise soit 'localPath' soit 'server' 'port' */
if(localPath)
{
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
dynSetAs(e, &ctx->localSocket, localPath);
/* localPath doit contenir le chemin complet d'un "fichier" unique pour la socket locale (exemple: /tmp/wsock_1234.sock et C:\\Temp\\wsock_1234.sock) */
if(ctx->localSocket.mLg >= sizeof(addr.sun_path))
{
dynSetLen(e, &ctx->localSocket, 0);
return WSOCKET_ERROR;
}
strcpy(addr.sun_path, ctx->localSocket.mPtr); /* la gestion du fichier socket local est laisse a la gestion du socket serveur en ecoute */
sa = (struct sockaddr *)&addr;
sofsa = sizeof(addr);
}
else
{
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.sin_addr) != 1)
#endif
{
// no ip v4 format, search for name
if((serv = gethostbyname(server->mPtr)) == NULL)
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return WSOCKET_ERROR;
}
//addr.sin_addr.s_addr = ((struct in_addr *)(serv->h_addr))->s_addr;
//addr.sin_addr.s_addr = (*(long *)(serv->h_addr));
memcpy(&addr.sin_addr, serv->h_addr_list[0], serv->h_length);
}
sa = (struct sockaddr *)&addr;
sofsa = sizeof(addr);
}
/* laisser en non bloquant */
int ret = connect(sock, sa, sofsa);
#ifdef WINLIB
if (ret == SOCKET_ERROR)
{
if(WSAGetLastError() != WSAEWOULDBLOCK)
{
ctx->err = GetSocketError();
closesocket(sock);
return WSOCKET_ERROR;
}
}
#else
if (ret < 0 && errno != EINPROGRESS)
{
ctx->err = GetSocketError();
close(sock);
return WSOCKET_ERROR;
}
#endif
if(AddSocket(e, ctx, sock) != WSOCKET_OK)
{
#ifdef WINLIB
closesocket(sock);
#else
close(sock);
#endif
return WSOCKET_ERROR;
}
#ifdef WINLIB
FD_ZERO(&ctx->fds);
FD_SET(sock, &ctx->fds);
ctx->tv.tv_sec = 1; // revoir parametre
ctx->tv.tv_usec = 0;
ret = select(0, NULL, &ctx->fds, NULL, &ctx->tv);
#else
ctx->poll[ctx->posAddSocket].events = POLLOUT;
ret = poll(&ctx->poll[ctx->posAddSocket], 1, 1000); // revoir parametres
ctx->poll[ctx->posAddSocket].events = POLLIN;
#endif
if (ret <= 0)
{
ctx->err = GetSocketError();
// timeout (0) ou erreur (<0)
#ifdef WINLIB
closesocket(sock);
#else
close(sock);
#endif
DelSocket(e, ctx, sock);
return WSOCKET_ERROR;
}
else
return WSOCKET_OK;
}
WAPIDECL long SendSocket(env * e, modContextSocket * ctx, Socket sock, Socket socketToSend, number pid)
{
/* send socket using AF_UNIX local socket */
#ifndef WINLIB
struct msghdr msg = {0};
char buffer[CMSG_SPACE(sizeof(int))];
memset(buffer, 0, sizeof(buffer));
struct iovec io = {
.iov_base = (void *)"X", /* peu importe... */
.iov_len = 1
};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buffer;
msg.msg_controllen = sizeof(buffer);
struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg);
if(cmsg == NULL)
return -1;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &socketToSend, sizeof(socketToSend));
if(sendmsg(sock, &msg, 0) < 0)
return -1;
else
return OK;
/* */
#else
WSAPROTOCOL_INFO info = {0};
if(WSADuplicateSocket(socketToSend, pid, &info) == SOCKET_ERROR)
return -1;
var * v = &e->tmp_dynamic; // verifier que v assez grand pour info
if(dynCtrl(e, v, sizeof(info), FALSE))
return -1;
memcpy(v->ptr, &info, sizeof(info));
v->mLg = sizeof(info);
if(WriteSocket(e, ctx, sock, v) != WSOCKET_OK)
return -1;
else
return OK;
#endif
}
WAPIDECL long ReceiveSocket(env * e, modContextSocket * ctx, Socket sock, Socket * socketReceived)
{
/* receive socket from AF_UNIX local socket */
#ifndef WINLIB
struct msghdr msg = {0};
char buffer[CMSG_SPACE(sizeof(int))];
memset(buffer, 0, sizeof(buffer));
struct iovec io = {
.iov_base = (void *)"X", /* peu importe... */
.iov_len = sizeof(1)
};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buffer;
msg.msg_controllen = sizeof(buffer);
if(recvmsg(sock, &msg, 0) <= 0)
return -1;
if(msg.msg_flags & MSG_CTRUNC)
return -1;
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if(cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS || cmsg->cmsg_len < CMSG_LEN(sizeof(int)))
return -1; /* pas de socket valide recue */
memcpy(socketReceived, CMSG_DATA(cmsg), sizeof(*socketReceived));
return OK;
/* */
#else
var * v = &e->tmp_dynamic;
dynSetLen(e, v, 0);
if(ReadSocket(e, ctx, sock, v, 1000) != WSOCKET_OK) // 1 sec.
return -1;
WSAPROTOCOL_INFO info = {0};
if(v->mLg != sizeof(info))
return -1;
memcpy(&info, v->ptr, sizeof(info));
*socketReceived = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &info, 0, 0);
if(*socketReceived == INVALID_SOCKET)
return -1;
else
return OK;
#endif
}
WAPIDECL long AddSocket(env * e, modContextSocket * ctx, Socket sock)
{
#ifndef WINLIB
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
{
ctx->posAddSocket = cpt;
return WSOCKET_OK; // deja present : RAF
}
// ajouter
if(dynCtrl(e, &ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return WSOCKET_MEM_ERROR; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket.ptr;
ctx->posAddSocket = ctx->nbSocket++; // post incrementation car tableau base 0
ctx->poll[ctx->posAddSocket].fd = sock;
ctx->poll[ctx->posAddSocket].events = POLLIN;
return WSOCKET_OK;
#else
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
{
ctx->posAddSocket = cpt;
return WSOCKET_OK; // deja present : RAF
}
// ajouter
if(dynCtrl(e, &ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return WSOCKET_MEM_ERROR; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket.ptr;
ctx->posAddSocket = ctx->nbSocket++; // post incrementation car tableau base 0
ctx->poll[ctx->posAddSocket] = sock;
return WSOCKET_OK;
#endif
}
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);
#ifndef WINLIB
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)
#else
return poll(ctx->poll, ctx->nbSocket, timeoutMs);
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == 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)
#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)
WAPIDECL long WaitSocketForRead(env * e, modContextSocket * ctx, 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;
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
{
ctx->poll[cpt].events = POLLIN;
ctx->poll[cpt].revents = 0;
}
return poll(ctx->poll, ctx->nbSocket, timeoutMs);
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
#else
FD_ZERO(&ctx->fds);
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, &ctx->fds, NULL, NULL, &ctx->tv);
#endif
}
WAPIDECL long WaitSocketForWrite(env * e, modContextSocket * ctx, int timeoutMs)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
{
ctx->poll[cpt].events = POLLOUT;
ctx->poll[cpt].revents = 0;
}
return poll(ctx->poll, ctx->nbSocket, timeoutMs);
// socket pret a l'ecriture si (ctx->poll[cpt].revents & POLLOUT) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
#else
FD_ZERO(&ctx->fds);
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, NULL, &ctx->fds, NULL, &ctx->tv);
#endif
}
WAPIDECL long WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
{
ctx->poll[cpt].events = POLLIN;
ctx->poll[cpt].revents = 0;
return poll(&ctx->poll[cpt], 1, timeoutMs);
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
}
#else
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
{
FD_ZERO(&ctx->fds);
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, &ctx->fds, NULL, NULL, &ctx->tv);
}
#endif
return WSOCKET_ERROR;
}
WAPIDECL long WaitOneSocketForWrite(env * e, modContextSocket * ctx, Socket sock, int timeoutMs)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
{
ctx->poll[cpt].events = POLLOUT;
ctx->poll[cpt].revents = 0;
return poll(&ctx->poll[cpt], 1, timeoutMs);
// socket pret a l'ecriture si (ctx->poll[cpt].revents & POLLOUT) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
}
#else
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
{
FD_ZERO(&ctx->fds);
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, NULL, &ctx->fds, NULL, &ctx->tv);
}
#endif
return WSOCKET_ERROR;
}
WAPIDECL void FreeSocket(env * e, modContextSocket * ctx, Socket sock)
{
shutdown(sock, 2);
/* supprimer le fichier d'un socket unix (local) - uniquement au moment de la liberation du socket serveur en ecoute */
#ifndef WINLIB
shutdown(sock, SHUT_RDWR); // inutile a cause de SO_LINGER = 1 !?
close(sock);
#else
shutdown(sock, SD_BOTH); // inutile a cause de SO_LINGER = 1 !?
closesocket(sock);
#endif
if(sock == ctx->servSock)
DeleteLocalSocketFile(e, ctx);
DelSocket(e, ctx, sock);
}
@@ -289,14 +717,23 @@ WAPIDECL int GetSocketError()
#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)
WAPIDECL int SocketWouldBlock()
{
int packetLg = 10000; // parametre ?
int timeoutMs = 100; // parametre ?
int err = GetSocketError();
#ifdef WINLIB
return (err == WSAEWOULDBLOCK || err == WSAEINTR);
#else
return (err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
#endif
}
// 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, long timeoutMs)
{
int packetLg = ctx->packet;
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(;;)
@@ -305,56 +742,74 @@ WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * dat
int cr = WaitOneSocketForRead(e, ctx, sock, timeoutMs);
if(cr < 0)
{
if(errno == EINTR)
continue; // reprendre si signal
return -1; /* erreur */
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
if(cr == 0)
return nbTot; /* timeout : renvoi des donnees eventuellement deja lues */
return WSOCKET_OK; /* timeout : renvoi des donnees eventuellement deja lues */
/* */
if( ! dynCtrl(e, data, data->mLg + packetLg, TRUE))
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
{
return -2; // erreur memoire
return WSOCKET_MEM_ERROR; // erreur memoire
}
int nbRead = read(sock, data->mPtr + data->mLg, packetLg);
#ifdef WINLIB
int nbRead = recv(sock, data->mPtr + data->mLg, packetLg, 0);
#else
int nbRead = recv(sock, data->mPtr + data->mLg, packetLg, 0);
#endif
if(nbRead < 0)
{
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
continue; // reprendre si signal
return -1; /* erreur */
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
if(nbRead == 0)
return -1; /* fin de lecture car fin du client */
if(nbRead == 0 && nbTot == 0)
return WSOCKET_END_CONNECT; /* fin de lecture car fin de la comm - A REVOIR */
/* nbRead positif ici */
data->mLg += nbRead;
dynSetLen(e, data, data->mLg + nbRead);
nbTot += nbRead;
if(nbRead < packetLg)
return WSOCKET_OK;
}
}
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data)
{
//int timeoutMs = 100; // parametre ?
long len = data->mLg, nbTot = 0;
long len = data->mLg, nbTot = 0, timeoutMs = 1000;
if(len == 0)
return 0;
return WSOCKET_OK;
/* */
for(;;)
{
int nbWrite = write(sock, data->mPtr + nbTot, len);
if(nbWrite == 0)
return -1; /* fin du client */
int cr = WaitOneSocketForWrite(e, ctx, sock, timeoutMs);
if(cr < 0)
{
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
/* */
#ifdef WINLIB
int nbWrite = send(sock, data->mPtr + nbTot, (int)len, 0);
#else
int nbWrite = send(sock, data->mPtr + nbTot, len, MSG_NOSIGNAL); /* inutile sous Windows et n'arrive QUE en ecriture ! */
#endif
if(nbWrite == 0 && nbTot == 0)
return WSOCKET_END_CONNECT; /* fin d'ecriture car fin de la comm - A REVOIR */
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 */
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
len -= nbWrite;
nbTot += nbWrite;
if(len <= 0)
return nbTot; /* OK */
return WSOCKET_OK;
}
}
+85
View File
@@ -0,0 +1,85 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "langage.h"
#include "dynamic.h"
#include "sqlite3.h"
typedef struct {
sqlite3 * sl3Handle;
sqlite3_stmt * sl3Request, * sl3Begin, * sl3Commit, * sl3Rollback, * sl3Cursor;
Dynamic confTable, stmt;
Dynamic request, pkfilter, colPk, colPkType, colAll, colAllType, error;
long nbStmt;
} modCtxSl3;
enum {
SL3ERR_PREPARE = 1,
SL3ERR_BIND = 2,
SL3ERR_NOPK = 3,
SL3ERR_NOTABLEINFO = 4,
SL3ERR_PREPARERW = 5,
SL3ERR_NORECORD = 6,
SL3ERR_COLTYPE = 7,
SL3ERR_READLOCK = 8,
SL3ERR_STEP = 9,
SL3ERR_WRITELOCK = 10,
SL3ERR_CREATE = 11,
SL3ERR_OPEN = 12,
SL3ERR_MEM = 13,
SL3ERR_TABLENOTPREP = 14,
SL3ERR_FETCH = -1
};
WAPIDECL void initSl3(env * e, modCtxSl3 * ctx);
WAPIDECL void freeSl3(env * e, modCtxSl3 * ctx);
WAPIDECL char * getErrorSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long openSl3(env * e, modCtxSl3 * ctx, const char * base);
WAPIDECL long createSl3(env * e, modCtxSl3 * ctx, const char * base);
WAPIDECL void closeSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long beginSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long commitSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long rollbackSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long prepare_rwSl3(env * e, modCtxSl3 * ctx, char * table);
WAPIDECL void remove_rwSl3(env * e, modCtxSl3 * ctx, char * table);
WAPIDECL long getDescSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * desc);
WAPIDECL long readSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * key, Dynamic * record);
WAPIDECL long writeSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * record);
WAPIDECL long cursorSl3(env * e, modCtxSl3 * ctx, Dynamic * request, Dynamic * param);
WAPIDECL long fetchSl3(env * e, modCtxSl3 * ctx, Dynamic * record, long count);
WAPIDECL long createTableSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * colName, Dynamic * colType, long nbPk);
WAPIDECL long removeTableSl3(env * e, modCtxSl3 * ctx, char * table);
/*
1 base = 1 fichier sur disque (rm pour supprimer la base...), open ouvre ou cree la base (il suffit de verifier si le fichier existe...). Encodage = UTF-8
pas d'asynchrone (creer des threads/process) ; PRAGMA table_info(<table>) donne les infos sur une table (colonnes, types, PK etc.) ; pas de notion de schema (tout est dans la meme "base")
syntaxe pour binding dans requetes : ?1 ?2 ou :param1 $param2 @param3
docs : https://sqlite.org/capi3ref.html
sqlite3.c: The SQLite amalgamation source file
sqlite3.h: The header file that accompanies sqlite3.c and defines the C-language interfaces to SQLite.
shell.c: The command-line interface program itself.
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -lm -o sqlite3
gcc -fPIC -shared sqlite3.c -o libsqlite3.so -lpthread -ldl -lm
*/
+268826
View File
File diff suppressed because it is too large. Load diff
+14335
View File
File diff suppressed because it is too large. Load diff
+507
View File
@@ -0,0 +1,507 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "sqlite.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
#define SQLITE_TYPE_TEXT "TEXT"
#define SQLITE_TYPE_INTEGER "INTEGER"
WAPIDECL void initSl3(env * e, modCtxSl3 * ctx)
{
dynInit(e, &ctx->stmt, DYN_LGMIN);
dynInit(e, &ctx->confTable, DYN_LGMIN);
dynInit(e, &ctx->request, DYN_LGMIN);
dynInit(e, &ctx->pkfilter, DYN_LGMIN);
dynInit(e, &ctx->colPk, DYN_LGMIN);
dynInit(e, &ctx->colPkType, DYN_LGMIN);
dynInit(e, &ctx->colAll, DYN_LGMIN);
dynInit(e, &ctx->colAllType, DYN_LGMIN);
dynInit(e, &ctx->error, DYN_LGMIN);
ctx->nbStmt = 0;
}
WAPIDECL void freeSl3(env * e, modCtxSl3 * ctx)
{
dynFree(e, &ctx->stmt);
dynFree(e, &ctx->confTable);
dynFree(e, &ctx->request);
dynFree(e, &ctx->pkfilter);
dynFree(e, &ctx->colPk);
dynFree(e, &ctx->colPkType);
dynFree(e, &ctx->colAll);
dynFree(e, &ctx->colAllType);
dynFree(e, &ctx->error);
}
WAPIDECL char * getErrorSl3(env * e, modCtxSl3 * ctx)
{
dynLet(e, &ctx->error, (char *)sqlite3_errmsg(ctx->sl3Handle), DYN_LGNONE);
return ctx->error.mPtr;
}
WAPIDECL long openSl3(env * e, modCtxSl3 * ctx, const char * base)
{
if(sqlite3_open_v2(base, &ctx->sl3Handle, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK)
return SL3ERR_OPEN;
else
{
dynSetLen(e, &ctx->stmt, 0);
ctx->nbStmt = 0;
dynSetLen(e, &ctx->confTable, 0);
// preparation des requetes de transaction
if(sqlite3_prepare_v2(ctx->sl3Handle, "BEGIN TRANSACTION", -1, &ctx->sl3Begin, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
if(sqlite3_prepare_v2(ctx->sl3Handle, "COMMIT TRANSACTION", -1, &ctx->sl3Commit, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
if(sqlite3_prepare_v2(ctx->sl3Handle, "ROLLBACK TRANSACTION", -1, &ctx->sl3Rollback, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
return OK; // connexion a une base ; pour la creer si elle n'existe pas : " | SQLITE_OPEN_CREATE "
}
}
WAPIDECL long createSl3(env * e, modCtxSl3 * ctx, const char * base)
{
if(sqlite3_open_v2(base, &ctx->sl3Handle, SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
return SL3ERR_CREATE;
sqlite3_close(ctx->sl3Handle);
return openSl3(e, ctx, base);
}
WAPIDECL void closeSl3(env * e, modCtxSl3 * ctx)
{
/* finalize stmt */
sqlite3_stmt ** p = (sqlite3_stmt **)ctx->stmt.ptr;
long cpt;
for(cpt = 0; cpt < ctx->nbStmt * 2; cpt++)
sqlite3_finalize(p[cpt]);
/* */
sqlite3_finalize(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Cursor);
sqlite3_finalize(ctx->sl3Begin);
sqlite3_finalize(ctx->sl3Commit);
sqlite3_finalize(ctx->sl3Rollback);
/* */
sqlite3_close(ctx->sl3Handle);
}
WAPIDECL long beginSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Begin);
if(sqlite3_step(ctx->sl3Begin) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long commitSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Commit);
if(sqlite3_step(ctx->sl3Commit) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long rollbackSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Rollback);
if(sqlite3_step(ctx->sl3Rollback) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long prepare_rwSl3(env * e, modCtxSl3 * ctx, char * table)
{
/*
confTable<1,x> = nom table
confTable<2,x> = nom colonne de la PK, dans l'ordre, separees par ","
confTable<3,x> = type de la colonne de la PK, lie avec confTable<2,x>
confTable<4,x> = nom de toutes les colonnes de la table, dans l'ordre, separees par ","
confTable<5,x> = type de toutes les colonnes de la table, dans l'ordre, lie avec confTable<4,x>
stmt[(x-1)*2] et stmt[(x-1)*2+1] = read/write stmt
*/
sqlite3_stmt * sl3read, * sl3write;
/* */
sqlite3_finalize(ctx->sl3Request);
dynLet(e, &ctx->request, "PRAGMA table_info(?1);", 22);
/* cid;name;type;notnull;dfltvalue;pk
0;kcust;INTEGER;0;;1
1;kind;INTEGER;0;;2
2;ident;TEXT;0;;0 */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
if(sqlite3_bind_text(ctx->sl3Request, 1, table, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
/* */
long nb = 0, cpt = 0;
/* read */
dynSetLen(e, &ctx->pkfilter, 0);
dynSetLen(e, &ctx->colPk, 0);
dynSetLen(e, &ctx->colPkType, 0);
dynSetLen(e, &ctx->colAll, 0);
dynSetLen(e, &ctx->colAllType, 0);
dynLet(e, &ctx->request, "select * from ", 14);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " where ", DYN_LGNONE);
/* */
while(sqlite3_step(ctx->sl3Request) == SQLITE_ROW) // peut renvoyer == SQLITE_DONE si pas de ligne, ou == SQLITE_ROW pour chaque ligne, ou == SQLITE_ERROR en cas d'erreur
{
/* les numeros des colonnes sont en base 0 */
if(strcmp((const char *)sqlite3_column_text(ctx->sl3Request, 2), SQLITE_TYPE_TEXT) != 0) return SL3ERR_COLTYPE;
if(strcmp((const char *)sqlite3_column_text(ctx->sl3Request, 2), SQLITE_TYPE_INTEGER) != 0) return SL3ERR_COLTYPE;
/* */
nb++;
dynStoreSz(e, &ctx->colAll, sqlite3_column_int64(ctx->sl3Request, 0) + 1, DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE, ',', DYN_NONE);
dynStoreSz(e, &ctx->colAllType, sqlite3_column_int64(ctx->sl3Request, 0) + 1, DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 2), DYN_LGNONE, ',', DYN_NONE);
if(sqlite3_column_int64(ctx->sl3Request, 5) > 0) // si c'est une colonne de la PK
{
if(++cpt > 1)
dynConcatSz(e, &ctx->pkfilter, " and ", DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, " = ?", DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, Int32ToSz(cpt, FALSE, 0), DYN_LGNONE);
/* */
dynStoreSz(e, &ctx->colPk, sqlite3_column_int64(ctx->sl3Request, 5), DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE, ',', DYN_NONE);
dynStoreSz(e, &ctx->colPkType, sqlite3_column_int64(ctx->sl3Request, 5), DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 2), DYN_LGNONE, ',', DYN_NONE); // TEXT INTEGER
}
}
sqlite3_finalize(ctx->sl3Request);
// si reset avant finalize, on peut reutiliser la requete preparee (repartir des bind), sinon il faut la preparer a nouveau ; reset => bind => step
if(cpt > 0)
{
dynConcat(e, &ctx->request, &ctx->pkfilter);
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &sl3read, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
}
else
return SL3ERR_NOPK;
/* */
dynLet(e, &ctx->request, "REPLACE INTO ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, (char *)table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " (", DYN_LGNONE);
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, ") VALUES (", DYN_LGNONE);
for(long i = 1; i <= nb; i++)
{
dynConcatSz(e, &ctx->request, i > 1 ? ",?" : "?", DYN_LGNONE);
dynConcatSz(e, &ctx->request, Int32ToSz(i, FALSE, 0), DYN_LGNONE);
}
dynConcatSz(e, &ctx->request, ") where ", DYN_LGNONE);
dynConcat(e, &ctx->request, &ctx->pkfilter);
if(nb > 0)
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &sl3write, NULL) != SQLITE_OK)
{
sqlite3_finalize(sl3write);
return SL3ERR_PREPARE;
}
/* memo dans ctx */
if(nb > 0)
{
if(dynCtrl(e, &ctx->stmt, (ctx->nbStmt + 1) * 2 * sizeof(pointeur), TRUE))
{
sqlite3_finalize(sl3read);
sqlite3_finalize(sl3write);
return SL3ERR_MEM;
}
sqlite3_stmt ** p = (sqlite3_stmt **)ctx->stmt.ptr;
p[ctx->nbStmt * 2] = sl3read;
p[ctx->nbStmt * 2 + 1] = sl3write;
ctx->nbStmt++;
long pos = dynDcount(e, &ctx->confTable, cVM, 1, cFM) + 1;
dynStoreSz(e, &ctx->confTable, 1, pos, (char *)table, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 2, pos, ctx->colPk.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 3, pos, ctx->colPkType.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 4, pos, ctx->colAll.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 5, pos, ctx->colAllType.mPtr, DYN_LGNONE, cFM, cVM);
/* */
return OK;
}
else
return SL3ERR_NOTABLEINFO;
}
WAPIDECL void remove_rwSl3(env * e, modCtxSl3 * ctx, char * table)
{
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return;
sqlite3_stmt * stmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2]; // read
sqlite3_finalize(stmt);
stmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2 + 1]; // write
sqlite3_finalize(stmt);
dynStoreSz(e, &ctx->confTable, 1, posTable, "@", 1, cFM, cVM);
/* remplacer celle supprimee par la derniere dans confTable et stmt ?? */
}
WAPIDECL long getDescSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * desc)
{
/* renvoie la liste des colonnes/cles de la table si "preparee" */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_TABLENOTPREP;
/* */
dynSetLen(e, desc, 0);
dynField(e, &ctx->confTable, &ctx->request, 4, posTable, cFM, cVM, 1); // colonnes
dynStore(e, desc, 1, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 5, posTable, cFM, cVM, 1); // type
dynStore(e, desc, 2, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 2, posTable, cFM, cVM, 1); // colonnes PK
dynStore(e, desc, 3, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 3, posTable, cFM, cVM, 1); // colonnes PK type
dynStore(e, desc, 4, DYN_NONE, &ctx->request, cFM, DYN_NONE);
return OK;
}
WAPIDECL long readSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * key, Dynamic * record)
{
/* !! champs de key et record en VM !! */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
{
if(prepare_rwSl3(e, ctx, table) != OK)
return SL3ERR_PREPARERW;
posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_PREPARERW;
}
/* table prepare_rw ok ici, faire les bind sur la cle (au moins 1 colonne) */
sqlite3_stmt * readStmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2];
sqlite3_reset(readStmt);
/* */
dynField(e, &ctx->confTable, &ctx->colPkType, 3, posTable, cFM, cVM, 1); // type des colonnes de la PK
long pk, nbPk = dynDcount(e, &ctx->colPkType, ',', DYN_NONE, DYN_NONE);
if(nbPk == 0) return SL3ERR_NOPK;
for(pk = 1; pk <= nbPk; pk++)
{
dynField(e, &ctx->colPkType, &ctx->request, pk, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne de la PK
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, key, &ctx->request, pk, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_text(readStmt, 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, key, &ctx->request, pk, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_int64(readStmt, 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
int cr = sqlite3_step(readStmt);
if(cr == SQLITE_ROW)
{
dynSetLen(e, record, 0);
dynField(e, &ctx->confTable, &ctx->colAllType, 5, posTable, cFM, cVM, 1); // type des colonnes
long col, nbCol = dynDcount(e, &ctx->colAllType, ',', DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, &ctx->colAllType, &ctx->request, col, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
dynStoreSz(e, record, col, DYN_NONE, (char *)sqlite3_column_text(readStmt, col - 1), DYN_LGNONE, cVM, DYN_NONE);
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
dynStoreNumber(e, record, col, DYN_NONE, sqlite3_column_int64(readStmt, col - 1), cVM, DYN_NONE);
else
return SL3ERR_COLTYPE;
}
return OK;
}
else if(cr == SQLITE_DONE)
return SL3ERR_NORECORD;
else if(cr == SQLITE_BUSY)
return SL3ERR_READLOCK;
else
return SL3ERR_STEP;
}
WAPIDECL long writeSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * record)
{
/* !! champs de record en VM !! */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
{
if(prepare_rwSl3(e, ctx, table) != OK)
return SL3ERR_PREPARERW;
posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_PREPARERW;
}
/* table prepare_rw ok ici, faire les bind sur la cle (au moins 1 colonne) */
sqlite3_stmt * writeStmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2 + 1];
sqlite3_reset(writeStmt);
/* */
dynField(e, &ctx->confTable, &ctx->colAllType, 5, posTable, cFM, cVM, 1); // type des colonnes
long col, nbCol = dynDcount(e, &ctx->colAllType, ',', DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, &ctx->colAllType, &ctx->request, col, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, record, &ctx->request, col, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_text(writeStmt, 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, record, &ctx->request, col, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_int64(writeStmt, 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
int cr = sqlite3_step(writeStmt);
if(cr == SQLITE_DONE)
return OK;
else if(cr == SQLITE_BUSY)
return SL3ERR_WRITELOCK;
else
return SL3ERR_STEP;
}
WAPIDECL long cursorSl3(env * e, modCtxSl3 * ctx, Dynamic * request, Dynamic * param)
{
/* param<1> = valeur champ (separateur VM) ; param<2> = type champ TEXT/INTEGER (separateur VM) */
sqlite3_finalize(ctx->sl3Cursor);
if(sqlite3_prepare_v2(ctx->sl3Handle, request->mPtr, -1, &ctx->sl3Cursor, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
/* binding */
dynField(e, param, &ctx->colAll, 1, DYN_NONE, cFM, DYN_NONE, 1);
dynField(e, param, &ctx->colAllType, 2, DYN_NONE, cFM, DYN_NONE, 1);
long col, nbCol = dynDcount(e, &ctx->colAllType, cVM, DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, param, &ctx->request, 2, col, cFM, cVM, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, param, &ctx->request, 1, col, cFM, cVM, 1); // valeur
if(sqlite3_bind_text(ctx->sl3Cursor, col - 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, param, &ctx->request, 1, col, cFM, cVM, 1); // valeur
if(sqlite3_bind_int64(ctx->sl3Cursor, col - 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
return OK;
}
WAPIDECL long fetchSl3(env * e, modCtxSl3 * ctx, Dynamic * record, long count)
{
/* count = 0 => tout lire en une seule fois ; renvoi le nombre d'enregs lus ; SL3ERR_FETCH si erreur */
dynSetLen(e, record, 0);
long nb = 0, cols, cpt;
int cr;
while((cr = sqlite3_step(ctx->sl3Cursor)) == SQLITE_ROW && (count == 0 || nb < count))
{
nb++;
/* remplir le record avec les donnees de la ligne */
cols = sqlite3_column_count(ctx->sl3Cursor); // si besoin : strcpy(s, sqlite3_column_name(ctx->sl3Request, 0));
for(cpt = 0; cpt < cols; cpt++)
dynStoreSz(e, record, nb, cpt + 1, (char *)sqlite3_column_text(ctx->sl3Cursor, cpt), DYN_LGNONE, cFM, cVM);
}
if(cr != SQLITE_DONE && cr != SQLITE_ROW)
return SL3ERR_FETCH;
else
return nb;
}
WAPIDECL long createTableSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * colName, Dynamic * colType, long nbPk)
{
sqlite3_finalize(ctx->sl3Request);
/* exemple
CREATE TABLE ftest (kcust INTEGER, kind INTEGER, ident TEXT,
CONSTRAINT ftrans_pk PRIMARY KEY (kcust,kind));
*/
/* colName et colType en VM, separateur = ',' ; type = TEXT/INTEGER */
dynLet(e, &ctx->request, "CREATE TABLE ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " (", DYN_LGNONE);
long col, nbCol = dynDcount(e, colName, ',', DYN_NONE, DYN_NONE);
if(nbCol <= 0)
return SL3ERR_NOTABLEINFO;
if(nbPk <= 0 || nbPk > nbCol)
return SL3ERR_NOPK;
for(col = 1; col <= nbCol; col++)
{
dynField(e, colName, &ctx->colAll, col, DYN_NONE, ',', DYN_NONE, 1);
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, " ", DYN_LGNONE);
dynField(e, colType, &ctx->colAllType, col, DYN_NONE, ',', DYN_NONE, 1);
dynConcat(e, &ctx->request, &ctx->colAllType);
if(col > 1)
dynConcatSz(e, &ctx->request, ",", DYN_LGNONE);
}
/* les <nbPk> premieres colonnes sont la cle primaire, dans l'ordre */
dynConcatSz(e, &ctx->request, ", CONSTRAINT ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, "_pk PRIMARY KEY (", DYN_LGNONE);
dynField(e, colName, &ctx->colAll, col, DYN_NONE, ',', DYN_NONE, nbPk); // les <nbPk> premieres colonnes sont la cle primaire, dans l'ordre
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, "))", DYN_LGNONE);
/* */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
int cr = sqlite3_step(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Request);
if(cr == SQLITE_DONE)
return OK;
else
return SL3ERR_STEP;
}
WAPIDECL long removeTableSl3(env * e, modCtxSl3 * ctx, char * table)
{
remove_rwSl3(e, ctx, table);
/* */
sqlite3_finalize(ctx->sl3Request);
dynLet(e, &ctx->request, "DROP TABLE ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
/* */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
int cr = sqlite3_step(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Request);
if(cr == SQLITE_DONE)
return OK;
else
return SL3ERR_STEP;
}
/*
1 base = 1 fichier sur disque (rm pour supprimer la base...), open ouvre ou cree la base (il suffit de verifier si le fichier existe...). Encodage = UTF-8
pas d'asynchrone (creer des threads/process) ; PRAGMA table_info(<table>) donne les infos sur une table (colonnes, types, PK etc.) ; pas de notion de schema (tout est dans la meme "base")
syntaxe pour binding dans requetes : ?1 ?2 ou :param1 $param2 @param3
docs : https://sqlite.org/capi3ref.html
sqlite3.c: The SQLite amalgamation source file
sqlite3.h: The header file that accompanies sqlite3.c and defines the C-language interfaces to SQLite.
shell.c: The command-line interface program itself.
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -lm -o sqlite3
gcc -fPIC -shared sqlite3.c -o libsqlite3.so -lpthread -ldl -lm
*/
+79
View File
@@ -0,0 +1,79 @@
/* **********************************************
__ __ __
\ \/ \/ / 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"
#include <libssh/libssh.h>
#include <libssh/sftp.h>
/* codes a passer a la fonction setError */
enum {
WSSH_MEM_ERROR = -2,
WSSH_ERROR = -1,
WSSH_OK = 0,
WSSH_SESSION = 1,
WSSH_SESSION_CONNECT = 2,
WSSH_AUTH = 3,
WSSH_CHANNEL = 4,
WSSH_CHANNEL_OPEN = 5,
WSSH_WRITE = 6,
WSSH_READ = 7,
WSSH_EXEC = 8,
WSSH_MODE = 9,
WSSH_SFTP = 10,
WSSH_SFTP_INIT = 11
};
enum {
WSSH_EXEC_MODE = 1,
WSSH_TERMINAL_MODE = 0
};
typedef struct {
ssh_session session;
ssh_channel channel; /* commandes console */
sftp_session sftp;
/* */
int err; /* erreur specifique au module */
int packet; /* taille des paquets lus un par un */
int execMode; /* TRUE si channelExec, FALSE si pseudo terminal */
} modContextSsh;
WAPIDECL void initSsh(env * e, modContextSsh * ctx);
WAPIDECL void freeSsh(env * e, modContextSsh * ctx);
WAPIDECL long setSession(env * e, modContextSsh * ctx, Dynamic * host, Dynamic * user, Dynamic * pwd);
WAPIDECL void freeSession(env * e, modContextSsh * ctx);
WAPIDECL long setChannel(env * e, modContextSsh * ctx, int mode);
WAPIDECL void freeChannel(env * e, modContextSsh * ctx);
WAPIDECL long channelExec(env * e, modContextSsh * ctx, Dynamic * data, Dynamic * resultat, number timeout);
WAPIDECL long channelWrite(env * e, modContextSsh * ctx, Dynamic * data);
WAPIDECL long channelRead(env * e, modContextSsh * ctx, Dynamic * data, number timeout);
/* faire idem channel pour "transfert" (sftp) */
WAPIDECL long setSftp(env * e, modContextSsh * ctx);
WAPIDECL void freeSftp(env * e, modContextSsh * ctx);
+288
View File
@@ -0,0 +1,288 @@
/* **********************************************
__ __ __
\ \/ \/ / 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"
/* ============================================================================================= */
#include "ssh.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextSsh ctxSsh;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_WSSH_SESSION = 1,
EXMOD_WSSH_CHANNEL = 2,
EXMOD_WSSH_SFTP = 3,
EXMOD_WSSH_WRITECHANNEL = 4,
EXMOD_WSSH_EXECCHANNEL = 5,
EXMOD_WSSH_READCHANNEL = 6,
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Opening ssh session error",
"Opening ssh channel error",
"Opening sftp session error",
"Write channel error",
"Execute channel command error", // 5
"Read channel error"
};
/* ============================================================================================= */
#include "mod.c"
#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 */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initSsh(e, &p_etat->ctxSsh);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
freeSsh(e, &p_etat->ctxSsh);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "openSession", 11))
{
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramUsername = getParam(e, "username", 8);
var * paramPassword = getParam(e, "password", 8);
/* ouvre la connexion ssh au serveur */
if(paramHost == NULL || paramUsername == NULL || paramPassword == NULL)
exc = EX_MODPARAM;
else if(paramHost->type != VAR_DYNAMIC || paramUsername->type != VAR_DYNAMIC || paramPassword->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(setSession(e, &p_etat->ctxSsh, paramHost, paramUsername, paramPassword) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SESSION);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "endSession", 10))
{
/* ferme la connexion ssh au serveur */
freeSession(e, &p_etat->ctxSsh);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "execChannel", 11))
{
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
var * paramResponse = getParam(e, "response", 8);
var * paramTimeout = getParam(e, "timeout", 7);
/* envoi d'une commande "one shot", pas besoin du 'openChannel' ici, lecture du resultat avec 'readChannel' et renvoi du resultat dans response, timeout en sec. dans timeout */
if(paramCommand == NULL || paramResponse == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if(var_conv_num(e, paramTimeout, &timeout))
{
if(paramResponse->type != VAR_DYNAMIC)
var_let(e, paramResponse, &e->int_dynamic, FALSE, FALSE);
if(channelExec(e, &p_etat->ctxSsh, paramCommand, paramResponse, timeout) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_EXECCHANNEL);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "openChannel", 11))
{
/* ouvre un canal de type "terminal" avec le serveur
faire un 'readChannel' la premiere fois apres le 'openChannel', puis enchainer les ecritures (commandes) et lectures (resultat) */
if(setChannel(e, &p_etat->ctxSsh, WSSH_TERMINAL_MODE) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_CHANNEL);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "writeChannel", 12))
{
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
if(paramCommand == NULL)
exc = EX_MODPARAM;
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* envoi d'une commande au pseudo-terminal */
if(channelWrite(e, &p_etat->ctxSsh, paramCommand) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_WRITECHANNEL);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "readChannel", 11))
{
/* get param in the right order */
var * paramResponse = getParam(e, "response", 8);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramResponse == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramResponse->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* lecture du resultat d'une commande (stdout dans paramResponse) en mode terminal, timeout en sec. dans timeout */
number timeout;
if(var_conv_num(e, paramTimeout, &timeout))
{
if(channelRead(e, &p_etat->ctxSsh, paramResponse, timeout) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_READCHANNEL);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeChannel", 12))
{
/* ferme le channel mais laisse la connexion au serveur ouverte (mode terminal seulement, inutile en mode exec) */
freeChannel(e, &p_etat->ctxSsh);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "openSftp", 8))
{
/* ouvre un canal de type "transfert" avec le serveur */
if(setSftp(e, &p_etat->ctxSsh) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SFTP);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeSftp", 9))
{
/* ferme le canal "transfert" mais laisse la connexion au serveur ouverte */
freeSftp(e, &p_etat->ctxSsh);
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+307
View File
@@ -0,0 +1,307 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "ssh.h"
#ifdef WINLIB
#include <WinSock2.h>
#else
#include "poll.h"
#include <fcntl.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/*
unix : -lssh -lcrypto -lssl -lz (dependances openssl zlib, verification avec : ldd /usr/lib/libssh.so)
sudo apt update
sudo apt install -y \
openssl libssl-dev \
zlib1g zlib1g-dev \
libssh-dev
openssl → binaire en ligne de commande
libssl-dev → headers + librairies pour compiler en C
zlib1g → runtime
zlib1g-dev → headers (zlib.h) + .so
libssh-dev → headers et libs de développement
windows : libssh.lib (et libssh compile avec msvc sinon ko)
ajouter => libssl.lib libcrypto.lib zlib.lib ws2_32.lib (car dependances openssl, zlib, socket)
git clone https://github.com/microsoft/vcpkg
cd vcpkg
bootstrap-vcpkg.bat
vcpkg install libssh:x64-windows
vcpkg install zlib:x64-windows
vcpkg install openssl:x64-windows
+ compil/link => cl main.c /I"path\to\vcpkg\installed\x64-windows\include" /link /LIBPATH:"path\to\vcpkg\installed\x64-windows\lib" libssh.lib libssl.lib libcrypto.lib zlib.lib ws2_32.lib
=> repertoire ou se trouve vcpkg (install depuis git) :
C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows
À l'exécution il faut :
libssl-*.dll
libcrypto-*.dll
dans :
même dossier que .exe ou dans le PATH
=== CERTIFICAT auto signé
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes
avec windows, c'est pareil, sauf initsocket WAStartup, type SOCKET et pas int, closesocket() et il faut fournir un fichier ca (https://curl.se/ca/cacert.pem) pour la verification des certificats
https://kb.firedaemon.com/...openssl-binary-distributions : binaires openssl sous windows (3.5.6 LTS ok), ok avec libssh 0.12.x (eventuellement 0.11.x)
*/
/* ****** PRIVATE ************************ */
int ssh_read_timeout(env * e, modContextSsh * ctx, Dynamic * data, number timeout)
{
#ifndef WINLIB
struct pollfd fd;
fd.fd = ssh_get_fd(ctx->session),
fd.events = POLLIN;
/* lecture avec timeout */
int cr = poll(&fd, 1, timeout * 1000 / NUM_FACTEUR);
#else
WSAPOLLFD fd;
fd.fd = (SOCKET)ssh_get_fd(ctx->session);
fd.events = POLLRDNORM;
fd.revents = 0;
/* lecture avec timeout */
int cr = WSAPoll(&fd, 1, timeout * 1000 / NUM_FACTEUR);
#endif
if (cr == 0)
return SSH_AGAIN; /* pas de donnees ou timeout */
if (cr < 0)
return SSH_ERROR;
/* lecture des donnees presentes */
return ssh_channel_read(ctx->channel, data->mPtr + data->mLg, ctx->packet, 0); /* 0 signifie lire stdout, 1 pour stderr */
}
static int setSessionCloexec(ssh_session session)
{
#ifndef WINLIB
int fd = (int)ssh_get_fd(session);
int ret = fcntl(fd, F_GETFD);
if(ret != -1)
ret = fcntl(fd, F_SETFD, ret | FD_CLOEXEC);
return (ret == -1); /* TRUE si erreur */
#else
return 0;
#endif
}
/* ****** PUBLIC ************************ */
WAPIDECL void initSsh(env * e, modContextSsh * ctx)
{
ctx->packet = 16000;
ctx->execMode = WSSH_EXEC_MODE; /* for channel management */
ctx->channel = NULL;
ctx->session = NULL;
}
WAPIDECL void freeSsh(env * e, modContextSsh * ctx)
{
freeSession(e, ctx);
}
WAPIDECL long setSession(env * e, modContextSsh * ctx, Dynamic * host, Dynamic * user, Dynamic * pwd)
{
freeSession(e, ctx);
/* */
if((ctx->session = ssh_new()) == NULL)
return (ctx->err = WSSH_SESSION);
/* */
ssh_options_set(ctx->session, SSH_OPTIONS_HOST, host->mPtr);
ssh_options_set(ctx->session, SSH_OPTIONS_USER, user->mPtr);
/* */
if(ssh_connect(ctx->session) != SSH_OK)
{
ssh_free(ctx->session);
ctx->session = NULL;
return (ctx->err = WSSH_SESSION_CONNECT);
}
setSessionCloexec(ctx->session); /* permet fork + execv securises, une fois connecte */
/* */
if(ssh_userauth_password(ctx->session, NULL, pwd->mPtr) != SSH_AUTH_SUCCESS)
{
//ssh_channel_free(ctx->channel);
freeSession(e, ctx);
return (ctx->err = WSSH_AUTH);
}
return (ctx->err = WSSH_OK);
}
WAPIDECL void freeSession(env * e, modContextSsh * ctx)
{
freeChannel(e, ctx);
freeSftp(e, ctx);
if(ctx->session)
{
ssh_disconnect(ctx->session);
ssh_free(ctx->session);
ctx->session = NULL;
}
}
WAPIDECL long setChannel(env * e, modContextSsh * ctx, int mode)
{
freeChannel(e, ctx);
ctx->execMode = mode;
ssh_set_blocking(ctx->session, TRUE); /* bloquant */
/* */
if((ctx->channel = ssh_channel_new(ctx->session)) == NULL)
return (ctx->err = WSSH_CHANNEL);
/* */
if(ssh_channel_open_session(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
if(ctx->execMode == WSSH_EXEC_MODE)
return (ctx->err = WSSH_OK);
/* */
/* Allocation d'un pseudo-terminal + shell interactif (channel reste ouvert dans ce cas) */
if(ssh_channel_request_pty(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
if(ssh_channel_request_shell(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
return (ctx->err = WSSH_OK);
}
WAPIDECL void freeChannel(env * e, modContextSsh * ctx)
{
if(ctx->channel)
{
if(ctx->execMode == WSSH_TERMINAL_MODE)
{
ssh_channel_write(ctx->channel, "exit\n", 5);
ssh_channel_send_eof(ctx->channel);
}
ssh_channel_close(ctx->channel);
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
}
}
WAPIDECL long channelExec(env * e, modContextSsh * ctx, Dynamic * data, Dynamic * resultat, number timeout)
{
long cr;
cr = setChannel(e, ctx, WSSH_EXEC_MODE);
if(cr != WSSH_OK)
return (ctx->err = cr);
/* send command to channel, one shot (ssh_channel_request_exec ferme le channel a chaque commande) */
if(ssh_channel_request_exec(ctx->channel, data->mPtr) != SSH_OK)
cr = (ctx->err = WSSH_EXEC);
else
cr = channelRead(e, ctx, resultat, timeout); /* lecture du resultat en mode bloquant suite a l'envoi de la requete */
/* */
return cr;
}
WAPIDECL long channelWrite(env * e, modContextSsh * ctx, Dynamic * data)
{
if(ctx->execMode != WSSH_TERMINAL_MODE)
return (ctx->err = WSSH_MODE);
/* send command to channel */
if(ssh_channel_write(ctx->channel, data->mPtr, data->mLg) < 0)
return (ctx->err = WSSH_WRITE);
else
return (ctx->err = WSSH_OK);
/* le channel reste ouvert */
}
WAPIDECL long channelRead(env * e, modContextSsh * ctx, Dynamic * data, number timeout)
{
ssh_set_blocking(ctx->session, FALSE); /* non bloquant */
/* read response from serveur */
dynSetLen(e, data, 0);
/* Lire la sortie, mode non bloquant ici (explicite avec read_nonblocking) */
for(;;)
{
if(dynCtrl(e, data, data->mLg + ctx->packet, TRUE))
{
return (ctx->err = WSSH_MEM_ERROR); /* erreur memoire */
}
int nb = ssh_read_timeout(e, ctx, data, timeout);
/* */
if(nb == SSH_ERROR)
return (ctx->err = WSSH_READ);
if(nb == SSH_AGAIN || nb == 0)
return (ctx->err = WSSH_OK); /* rien a lire pour l'instant ou sortie en timeout ou fin des donnees */
/* */
if(nb > 0)
dynSetLen(e, data, data->mLg + nb);
/* continue reading */
}
}
WAPIDECL long setSftp(env * e, modContextSsh * ctx)
{
if((ctx->sftp = sftp_new(ctx->session)) == NULL)
return (ctx->err = WSSH_SFTP);
/* */
if(sftp_init(ctx->sftp) != SSH_OK)
{
freeSftp(e, ctx);
return (ctx->err = WSSH_SFTP_INIT);
}
return (ctx->err = WSSH_OK);
}
/*
sftp_file file = sftp_open(sftp, "/etc/hostname", O_RDONLY, 0); // NULL : erreur open
nbytes = sftp_read(file, buffer, sizeof(buffer)); // tant que nbytes > 0
sftp_close(file);
*/
WAPIDECL void freeSftp(env * e, modContextSsh * ctx)
{
if(ctx->sftp)
{
sftp_free(ctx->sftp);
ctx->sftp = NULL;
}
}
+280 -305
View File
@@ -25,29 +25,28 @@
#include <time.h>
#include <string.h>
#ifdef WINLIB
#include "windows.h"
#else
#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"
#include "hashtable.h"
#ifdef WINLIB
#include "windows.h"
#else
#include <sys/utsname.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
@@ -55,17 +54,23 @@ enum {
EXMOD_SYSTEM_UNKNOWNVARENV = 2,
EXMOD_SYSTEM_SETENV = 3,
EXMOD_SYSTEM_UNSETENV = 4,
EXMOD_SYSTEM_GETHOST = 5,
EXMOD_SYSTEM_UNAME = 6,
EXMOD_SYSTEM_FORK = 7
EXMOD_SYSTEM_UNAME = 5,
EXMOD_CMDLINE_ARG = 6,
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Cannot create tmp file",
"Unknown environment variable",
"set environment variable error",
"delete environment variable error",
"Cannot get host name", // 5
"Cannot read command line arguments"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -76,108 +81,151 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// execute(command, returning, capturing)
// getEnv(nom, valeur)
// setEnv(nom, valeur, overwritting)
// getOS(nom) => int uname(struct utsname *buf);
// getHostname(nom, ip) => int uname(struct utsname *buf);
// TODO prevoir un mecanisme de securite, pour autoriser ou non certains fonctions dangereuses (execute, setenv)
//
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* 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 */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
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 || param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
var * paramReturnCode = getParam(e, "returnCode", 10);
var * paramCapturing = getParam(e, "capturing", 9);
if(paramCommand == NULL || paramReturnCode == NULL)
exc = EX_MODPARAM;
else if(!param2 || param2->type != VAR_NUMBER)
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
int cr, flagCapturing = (param3 != NULL);
if(paramReturnCode->type != VAR_NUMBER)
var_let(e, paramReturnCode, &e->int_number, FALSE, FALSE);
/* */
int cr, flagCapturing = (paramCapturing != NULL);
if(flagCapturing)
{
if(param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
}
if(flagCapturing && exc == OK)
{
dynSetLen(e, param3, 0);
if(paramCapturing->type != VAR_DYNAMIC)
var_let(e, paramCapturing, &e->int_dynamic, FALSE, FALSE);
/* */
dynSetLen(e, paramCapturing, 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;
long lg;
if( ! (lg = GetTempPathA(paramCapturing->mLgmax, paramCapturing->mPtr)))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
{
if(lg > paramCapturing->mLgmax)
{
if(dynCtrl(e, paramCapturing, lg, DYN_FALSE) == DYN_OK)
{
if( ! (lg = GetTempPathA(paramCapturing->mLgmax, paramCapturing->mPtr)))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
}
else
exc = EX_MEM;
}
if(exc == OK)
{
dynSetLen(e, paramCapturing, lg);
if(dynCtrl(e, &e->int_dynamic, MAX_PATH, DYN_FALSE) == DYN_OK)
{
if( ! GetTempFileNameA(paramCapturing->mPtr, "tmp", 0, e->int_dynamic.mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
dynSetLen(e, &e->int_dynamic, strlen(e->int_dynamic.mPtr));
}
else
exc = EX_MEM;
}
}
#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;
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
close(fd);
#endif
@@ -186,294 +234,150 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
if(flagCapturing)
{
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 ?!
dynSetAs(e, paramCapturing, paramCommand);
dynIns(e, paramCapturing, 1 + dynDcount(e, paramCapturing, '>', DYN_NONE, DYN_NONE), DYN_NONE, &e->int_dynamic, '>', DYN_NONE);
cr = system(paramCapturing->mPtr);
dynRead(e, paramCapturing, e->int_dynamic.mPtr);
remove(e->int_dynamic.mPtr); // purge fichier temp
}
else
{
cr = system(param1->mPtr);
cr = system(paramCommand->mPtr);
}
param2->num = cr * NUM_FACTEUR;
paramReturnCode->num = cr * NUM_FACTEUR;
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getEnv", 6))
{
p_etat->error = 0;
/* utilisation de dynRead qui fait le travail */
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
var * paramValue = getParam(e, "value", 5);
if(paramVarName == NULL || paramValue == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
char * varenv = getenv(param1->mPtr);
if(!varenv)
exc = EXMOD_SYSTEM_UNKNOWNVARENV;
if(paramValue->type != VAR_DYNAMIC)
var_let(e, paramValue, &e->int_dynamic, FALSE, FALSE);
char * varenv = getenv(paramVarName->mPtr);
if(varenv == NULL)
exc = setError(p_etat, EXMOD_SYSTEM_UNKNOWNVARENV);
else
{
int lg;
if(dynCtrl(e, param2, (lg = strlen(varenv)), DYN_FALSE) == DYN_OK)
dynLet(e, param2, varenv, lg);
if(dynCtrl(e, paramValue, (lg = strlen(varenv)), DYN_FALSE) == DYN_OK)
dynLet(e, paramValue, varenv, lg);
else
exc = EX_MEM;
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "createEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
var * paramValue = getParam(e, "value", 5);
if(paramVarName == NULL || paramValue == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
// verifier si existe avec getenv, si oui erreur
char * varenv = getenv(param1->mPtr);
char * varenv = getenv(paramVarName->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);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
else if (!SetEnvironmentVariableA(paramVarName->mPtr, paramValue->mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = setenv(param1->mPtr, param2->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
int cr = setenv(paramVarName->mPtr, paramValue->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "updateEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
var * paramValue = getParam(e, "value", 5);
if(paramVarName == NULL || paramValue == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
if (!SetEnvironmentVariableA(paramVarName->mPtr, paramValue->mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = setenv(param1->mPtr, param2->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
int cr = setenv(paramVarName->mPtr, paramValue->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "deleteEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
if(paramVarName == NULL)
exc = EX_MODPARAM;
else if(paramVarName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, NULL))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
if (!SetEnvironmentVariableA(paramVarName->mPtr, NULL))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = unsetenv(param1->mPtr); // suppression
int cr = unsetenv(paramVarName->mPtr); // suppression
if(cr != 0)
{
exc = EXMOD_SYSTEM_UNSETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_UNSETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getOS", 5))
{
p_etat->error = 0;
// uname() donne les infos
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramOScode = getParam(e, "OScode", 6);
if(paramOScode == NULL)
exc = EX_MODPARAM;
else
{
if(paramOScode->type != VAR_DYNAMIC)
var_let(e, paramOScode, &e->int_dynamic, FALSE, FALSE);
#ifdef WINLIB
dynLet(e, param1, "Windows", DYN_LGNONE);
dynLet(e, paramOScode, "Windows", DYN_LGNONE);
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
{
if(dynCtrl(e, param1, (lg = strlen(name.sysname)), DYN_FALSE) == DYN_OK)
dynLet(e, param1, name.sysname, lg);
if(dynCtrl(e, paramOScode, (lg = strlen(name.sysname)), DYN_FALSE) == DYN_OK)
dynLet(e, paramOScode, name.sysname, lg);
else
exc = EX_MEM;
}
else
{
exc = EXMOD_SYSTEM_UNAME;
setError(p_etat, errno);
}
exc = setError(p_etat, EXMOD_SYSTEM_UNAME);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getHostname", 11))
{
// TODO dans sockMod !!
p_etat->error = 0;
// uname() donne les infos
if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
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)
{
if(dynCtrl(e, param1, (lg = strlen(name.nodename)), DYN_FALSE) == DYN_OK)
{
dynLet(e, param1, name.nodename, lg);
// lecture ip
struct hostent * host = gethostbyname(param1->mPtr);
if(host)
{
dynLet(e, param2, inet_ntoa(*(struct in_addr *)host->h_addr_list[0]), DYN_LGNONE);
}
else
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, h_errno);
}
}
else
exc = EX_MEM;
}
else
{
setError(p_etat, errno);
exc = EXMOD_SYSTEM_UNAME;
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
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()
#else
pid_t fils = fork();
if(fils == -1)
{
exc = EXMOD_SYSTEM_FORK;
setError(p_etat, errno);
}
else
{
if(fils == 0)
e->ppid = 0; // process fils
else
e->ppid = fils; // process pere
}
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "wait", 4))
{
// TODO a supprimer, cf. processMod
#ifndef UNIX
// faire differemment sous windows : pas de wait dispo ? WaitForSingleObject()
#else
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
param1->num = waitpid(-1, NULL, WNOHANG) * NUM_FACTEUR; // renvoi le pid d'un fils qui s'est fini, 0 si pas de fils termine
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "sendSignal", 10))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPid = getParam(e, "pid", 3);
var * paramSignalNumber = getParam(e, "signalNumber", 12);
if(paramPid == NULL || paramSignalNumber == NULL)
exc = EX_MODPARAM;
else
{
number pid, numSignal;
if( var_conv_num(e,param1, &pid) && var_conv_num(e, param2, &numSignal) )
if( var_conv_num(e,paramPid, &pid) && var_conv_num(e, paramSignalNumber, &numSignal) )
{
pid /= NUM_FACTEUR;
numSignal /= NUM_FACTEUR;
@@ -519,27 +423,98 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "sleep", 5))
{
#ifdef WINLIB
if(param1->type != VAR_NUMBER)
/* get param in the right order */
var * paramDuration = getParam(e, "duration", 8);
if(paramDuration == NULL)
exc = EX_MODPARAM;
else if(paramDuration->type != VAR_DYNAMIC && paramDuration->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
number duration;
if(var_conv_num(e, paramDuration, &duration))
{
#ifdef WINLIB
// duree attente envoyee en secondes
Sleep(duration * 1000 / NUM_FACTEUR); // en millisec.
#else
// duree attente envoyee en secondes, avec les decimales
usleep(duration * (1000000 / NUM_FACTEUR)); // en microsec.
#endif
}
else
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;
// duree attente envoyee en secondes, avec les decimales
usleep(param1->num * (1000000 / NUM_FACTEUR)); // en microsec.
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "newProcess", 10))
{
/* get param in the right order */
var * paramArgs = getParam(e, "args", 4);
var * paramPid = getParam(e, "newPid", 6);
if(paramArgs == NULL || paramPid == NULL)
exc = EX_MODPARAM;
else if(paramArgs->type != VAR_DYNAMIC) /* progs w + arguments en FM */
exc = EX_MODPARAM;
else
{
if(paramPid->type != VAR_NUMBER)
var_let(e, paramPid, &e->int_number, FALSE, FALSE);
paramPid->num = 0; /* erreur par defaut */
/* lire GUV_ENV et GUV_WARGV{1} pour reconstituer la ligne de commande windows/unix */
var * va = &e->int_dynamic;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_WARGV), &va); // garder {1,1} = executeur W
var * ve = &e->tmp_dynamic;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_ENV), &ve); // wbin wsrc wlib {1,1-3}
if(va && ve)
{
dynStore(e, va, 2, DYN_NONE, ve, cVM, DYN_NONE);
dynField(e, va, ve, 1, DYN_NONE, cVM, DYN_NONE, 4); /* ve = execw wbin wsrc wlib en VM */
dynReplace(e, ve, cVM, cFM);
dynConcatSz(e, ve, sFM, 1);
dynConcat(e, ve, paramArgs); /* ve = execw wbin wsrc wlib progw argw1 etc. en FM */
dynInsSz(e, ve, 2, 1, "-WBIN", 5, cFM, ':');
dynInsSz(e, ve, 3, 1, "-WSRC", 5, cFM, ':');
dynInsSz(e, ve, 4, 1, "-WLIB", 5, cFM, ':');
/* ve (tmp_dynamic) contient la ligne de commande complete */
#ifdef WINLIB
dynReplace(e, ve, cFM, ' '); /* recree une ligne de commande */
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si);
if(CreateProcess(NULL, ve->mPtr, NULL, NULL, FALSE, e->demon ? CREATE_NO_WINDOW : CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) // ou DETACHED_PROCESS comme avec BACK !?
{
paramPid->num = pi.dwProcessId * NUM_FACTEUR; /* ok, code retour = pid du process cree */
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
#else
long pid = fork();
if(pid > 0)
{
/* dans le pere, retourner le pid du process cree */
paramPid->num = pid * NUM_FACTEUR;
}
else if(pid == 0)
{
/* dans le fils : execvp et sortie */
dynField(e, ve, va, 1, DYN_NONE, cFM, DYN_NONE, 1);
char ** argv = dynToTabPtr(e, ve, cFM);
execvp(va->mPtr, argv); /* attention : si programme interactif en front lance (cas exec 'calc') avec acces entree standard => generera une exception car ce n'est pas possible sous Unix (ok windows) */
/* ici, erreur de execvp */
_exit(127); /* mieux que exit(0) !? */
}
#endif
}
else
exc = setError(p_etat, EXMOD_CMDLINE_ARG);
}
}
/* ============================================================================================= */
else
{
setError(p_etat, 0);
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+88 -55
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.
@@ -27,22 +27,30 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_xxx = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Template error"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -51,92 +59,117 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
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
// - - - - - - - - - - - - - - - - - - - -
/* 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 */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
//
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == 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
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
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);
/* get param in the right order */
var * param = getParam(e, "xxxParam", 8);
if(param == NULL)
exc = EX_MODPARAM;
else if(param->type != VAR_DYNAMIC && param->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
number x;
if(var_conv_num(e, param, &x))
exc = OK;
else
exc = setError(p_etat, EXMOD_xxx);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+23 -3
View File
@@ -30,19 +30,23 @@
#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 */
/* gcc w_src/test.c -s -o exec/test -Wall -m64 -DUNIX -L./exec -l:libw.so -l:cipher_lib.so */
#include "encod.h"
#include "convert.h"
#include "cipher.h"
env e;
modContextCipher ctx;
int main(int argc, char * argv[])
{
init_env(&e);
//
Dynamic v, w;
Dynamic v, w, x;
dynInit(&e, &v, DYN_LGMIN);
dynInit(&e, &w, DYN_LGMIN);
dynInit(&e, &x, DYN_LGMIN);
//
dynLet(&e, &v, "test des encodages12", DYN_LGNONE);
printf("test base64: %s\n", v.mPtr);
@@ -56,8 +60,24 @@ int main(int argc, char * argv[])
hex2str(&e, &v, &w);
printf("hexa2str: %s\n", w.mPtr);
//
dynLet(&e, &v, "x#11yugjh#HDxxx", DYN_LGNONE);
long cr = dynEscapeHexaMark(&e, &v);
printf("escape hexamark (cr %ld): *%s* lg %lld\n", cr, v.mPtr, v.mLg);
//
cipherInit(&e, &ctx);
dynLet(&e, &x, "cle1234567890123", DYN_LGNONE);
dynLet(&e, &v, "ABCDEFGHIJKLMNOP123456", DYN_LGNONE);
printf("\ncipher_aes128: %s cle: %s\n", v.mPtr, x.mPtr);
cr = cipher_AES128(&e, &ctx, &x, &v, &w);
printf("lg chiffre: %lld cr:%ld\n", w.mLg, cr);
dynSetLen(&e, &v, 0);
cr = decipher_AES128(&e, &ctx, &x, &w, &v);
printf("decipher_aes128 (lg: %lld): *%s* cr:%ld\n", v.mLg, v.mPtr, cr);
cipherEnd(&e, &ctx);
//
dynFree(&e, &v);
dynFree(&e, &w);
dynFree(&e, &x);
//
return 0;
}
+75
View File
@@ -0,0 +1,75 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 <time.h>
#include "langage.h"
#include "dynamic.h"
typedef struct {
//*** pour chrono
number start, lap;
//*** pour chrono ; n'est pas un membre d'un objet => global a tous les appels (et n'est pas reentrant - ok en multi process uniquement...)
struct timespec sts;
//*** pour alarme
var alarmList; /* de type hashtable */
//*** pour horodate et alarm, uniquement var tmp
var * dhm, * offset;
struct tm * stm, * stmLocal;
//*** pour alarm, uniquement var tmp
var * delay, * gmt, * nbocc; /* number */
} modContextTime;
#define TIMESTAMP_ISO8601 "A-M-JTh:m:SF"
#define TIMESTAMP_OFFSET_UNKNOWN 999999 // A GARDER ???
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_ALARM_TRIGGERED = -1, /* pas une vraie erreur ici */
EXMOD_GETCLOCK = 1,
EXMOD_FORMAT_KO = 2,
EXMOD_OFFSET_KO = 3,
EXMOD_TIMEDATE_STRING_KO = 4,
EXMOD_TIMEDATE_CONTEXT_KO = 5,
EXMOD_ALARM_CONTEXT_KO = 6
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WAPIDECL void initTime(env * e, modContextTime * ctx);
WAPIDECL void freeTime(env * e, modContextTime * ctx);
WAPIDECL long startChrono(env * e, modContextTime * ctx);
WAPIDECL long getChrono(env * e, modContextTime * ctx, number * duration);
WAPIDECL int setNow(env * e, modContextTime * ctxTime, var * hashTime);
WAPIDECL int setFromTimestamp(env * e, modContextTime * ctxTime, var * hashTime, time_t dhm, long offset);
WAPIDECL int setFromString(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format);
WAPIDECL int getTimeDate(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format, int wantUTC);
WAPIDECL int activateAlarm(env * e, modContextTime * ctxTime, var * name, var * heureDebut, int utc, var * delaiSeconde, int occurences);
WAPIDECL int getNextActivation(env * e, modContextTime * ctxTime, var * name, var * hashTime);
WAPIDECL int getAlarmActive(env * e, modContextTime * ctxTime, var * name, number * active);
WAPIDECL int stopAlarm(env * e, modContextTime * ctxTime, var * name);
WAPIDECL int alarmHasTriggered(env * e, modContextTime * ctxTime, var * name, number reposition, number * triggered);
+251 -625
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.
@@ -20,9 +20,6 @@
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>
@@ -30,277 +27,38 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
/* ============================================================================================= */
#include "time.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
number start, lap;
//*** pour duree ; n'est pas un membre d'un objet => global a tous les appels (et n'est pas reentrant - ok en multi process uniquement...)
struct timespec sts;
//*** pour horodate
time_t dhm, decalageHoraire;
struct tm stm;
var v;
var * pv;
Dynamic horodate, valNum;
modContextTime ctx;
} modEtat;
#define HORODATE_ISO8601 "A-M-JTh:m:SF"
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_GETCLOCK = 1,
EXMOD_PARAMNUM = 2,
EXMOD_FORMAT_KO = 3,
EXMOD_JETLAG_KO = 4,
EXMOD_DURATION_GETCLOCK = 5
/* codes erreurs dans time.h */
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Read clock time error",
"Format unexpected, bad character",
"Offset error",
"Datetime string format incorrect",
"Internal datetime parameters error", // 5
"Internal alarm parameters error"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
/* fonction locale aux calculs de duree */
static int clock_gettime_monotonic(struct timespec * tv)
{
#ifdef UNIX
return clock_gettime(CLOCK_MONOTONIC, tv);
#else
/* cf stackoverflow */
static LARGE_INTEGER ticksPerSec;
LARGE_INTEGER ticks;
if (!ticksPerSec.QuadPart)
{
QueryPerformanceFrequency(&ticksPerSec);
if(!ticksPerSec.QuadPart)
return -1;
}
QueryPerformanceCounter(&ticks);
tv->tv_sec = (long)(ticks.QuadPart / ticksPerSec.QuadPart);
tv->tv_nsec = (long)(((ticks.QuadPart % ticksPerSec.QuadPart) * 1000000000) / ticksPerSec.QuadPart);
return 0;
#endif
}
/* fonction locale aux alarmes */
static void AddOneDay(env * e, modEtat * p_etat)
{
// horodate au format AAAA-MM-DDThh:mm:ss+99:99
// ajout de 1 jour au format "externe"
// nb jours de chaque mois, d'abord annee normale puis bisextile
static long nbj[24] = {31,28,31,30,31,30,31,31,30,31,30,31,
31,29,31,30,31,30,31,31,30,31,30,31};
long annee, mois, jour, bisextile = 0;
dynField(e, &p_etat->horodate, &p_etat->valNum, 1, 1, 'T', '-', 1);
annee = dynToNum(e, &p_etat->valNum, FALSE, 4);
dynField(e, &p_etat->horodate, &p_etat->valNum, 1, 2, 'T', '-', 1);
mois = dynToNum(e, &p_etat->valNum, FALSE, 2);
dynField(e, &p_etat->horodate, &p_etat->valNum, 1, 3, 'T', '-', 1);
jour = dynToNum(e, &p_etat->valNum, FALSE, 2);
if(annee % 4 == 0 && (annee % 100 != 0 || annee % 400 == 0))
bisextile = 12;
jour += 1;
if(jour > nbj[mois + bisextile - 1])
{
jour = 1;
mois += 1;
if(mois > 12)
{
mois = 1;
annee += 1;
}
}
sprintf(p_etat->horodate.mPtr, "%04ld", annee);
sprintf(p_etat->horodate.mPtr + 5, "%02ld", mois);
sprintf(p_etat->horodate.mPtr + 8, "%02ld", jour);
*(p_etat->horodate.mPtr + 4) = '-';
*(p_etat->horodate.mPtr + 7) = '-';
*(p_etat->horodate.mPtr + 10) = 'T';
}
/* fonctions locales aux horodates */
#define HORODATE_DECALAGEHORAIREINCONNU 999999
#define LIRE1(d,i,e) {if((e=e&&(*d))){i=(*d++);}if(!e)break;}
#define LIRE2(d,i,e) {if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';}}if(!e)break;}
#define LIRE4(d,i,e) {if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';}}}}if(!e)break;}
static int MajTm(modEtat * p_etat, const char * format, const char * date)
{
memset(&p_etat->stm, 0, sizeof(p_etat->stm));
p_etat->stm.tm_mday = 1; // le jour du mois ne demarre pas a 0 (ce que fait le numero de mois : 0 a 11)
p_etat->stm.tm_isdst = -1;
p_etat->decalageHoraire = HORODATE_DECALAGEHORAIREINCONNU;
//
int encore = TRUE;
int i, signe;
char * f = (char *)format, * d = (char *)date, c;
while((c = *f++) && encore)
{
switch(c)
{
case 'A':
LIRE4(d,i,encore);
p_etat->stm.tm_year = i - 1900;
break;
case 'a':
LIRE2(d,i,encore);
p_etat->stm.tm_year = i + 100; // pas d'annee avant 2000... mettre une annee pivot ? type si < 50, 20xx sinon 19xx ?
break;
case 'M':
LIRE2(d,i,encore);
p_etat->stm.tm_mon = i - 1;
break;
case 'J':
LIRE2(d,i,encore);
p_etat->stm.tm_mday = i;
break;
case 'h':
LIRE2(d,i,encore);
p_etat->stm.tm_hour = i;
break;
case 'm':
LIRE2(d,i,encore);
p_etat->stm.tm_min = i;
break;
case 's':
LIRE2(d,i,encore);
p_etat->stm.tm_sec = i;
break;
case 'S':
LIRE2(d,i,encore);
p_etat->stm.tm_sec = i;
LIRE1(d,i,encore);
if(i != ',') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
// 7 decimales maxi...
break;
case 'F':
LIRE1(d,i,encore);
if(i == 'Z') {p_etat->decalageHoraire=0;break;}
else if(i != '+' && i != '-') {encore=FALSE;break;}
if(i == '-') signe = -1 ; else signe = 1;
LIRE2(d,i,encore);
p_etat->decalageHoraire = signe * i * 3600;
LIRE1(d,i,encore);
if(i != ':') {d--;break;}
LIRE2(d,i,encore);
p_etat->decalageHoraire += signe * i * 60;
break;
default:
LIRE1(d,i,encore);
if(c != i) {encore=FALSE;break;}
break;
}
}
return encore; // true = ok, false = erreur
}
static time_t MkTimeTU(modEtat * p_etat)
{
// utilisation de l'agorithme http://howardhinnant.github.io/date_algorithms.html
// car pas de fonction directe dans time.h : mktime suppose que struct tm est locale
int y, m, d;
y = p_etat->stm.tm_year + 1900;
m = p_etat->stm.tm_mon + 1;
d = p_etat->stm.tm_mday;
//
if(m <= 2) y--;
if(y < 0) y -= 399;
int era = y / 400;
unsigned int yoe = (y - era * 400); // [0, 399]
unsigned int doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365]
unsigned int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
time_t t = (time_t)(era * 146097 + doe - 719468);
t = t * 86400 + p_etat->stm.tm_hour * 3600 + p_etat->stm.tm_min * 60 + p_etat->stm.tm_sec;
return t;
}
static void FormatTm(env * e, modEtat * p_etat, const char * format, time_t dhm, time_t decalageHoraire)
{
dynSetLen(e, &p_etat->horodate, 0);
char * p = (char *)format, c[2] = {0};
dhm += decalageHoraire;
p_etat->stm.tm_isdst = -1;
p_etat->stm = *gmtime(&dhm);
//
while((c[0] = *p++))
{
switch(c[0])
{
case 'A':
case 'Y':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_year + 1900, FALSE, 4), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'a':
case 'y':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_year % 100, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'M':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_mon + 1, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'J':
case 'D':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_mday, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'h':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_hour, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'm':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_min, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 's':
case 'S':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_sec, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'F':
if(decalageHoraire == 0)
dynConcatSz(e, &p_etat->horodate, "Z", 1);
else
{
dynConcatSz(e, &p_etat->horodate, decalageHoraire > 0 ? "+" : "-", 1);
//
dynLet(e, &p_etat->valNum, Int64ToSz(e, (abs(decalageHoraire) / 3600) % 100, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
//
dynConcatSz(e, &p_etat->horodate, ":", 1);
//
dynLet(e, &p_etat->valNum, Int64ToSz(e, (abs(decalageHoraire) % 3600) / 60, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
}
break;
default:
dynConcatSz(e, &p_etat->horodate, c, 1);
break;
}
}
}
/* fonctions locales au module FIN */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -309,437 +67,305 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
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
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODETAT;
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* 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 */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* 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
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
p_etat->start = 0;
p_etat->lap = 0;
dynInit(e, &p_etat->horodate, DYN_LGMIN);
dynInit(e, &p_etat->valNum, DYN_LGMIN);
// 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);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initTime(e, &p_etat->ctx);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeTime(e, &p_etat->ctx);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
//*** code specifique ici
dynFree(e, &p_etat->horodate);
dynFree(e, &p_etat->valNum);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1 == NULL)
exc = EX_MODPARAM;
else 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)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "startChrono", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; // variables en parametre du mauvais type
//
if (clock_gettime_monotonic(&p_etat->sts) == -1)
exc = setError(p_etat, EXMOD_GETCLOCK);
else
{
p_etat->start = p_etat->sts.tv_sec * NUM_FACTEUR + (p_etat->sts.tv_nsec / 10000);
param1->num = p_etat->start;
}
exc = setError(p_etat, startChrono(e, &p_etat->ctx));
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "lapChrono", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramDuration = getParam(e, "duration", 8);
if(paramDuration == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; // variables en parametre du mauvais type
//
if (clock_gettime_monotonic(&p_etat->sts) == -1)
exc = setError(p_etat, EXMOD_GETCLOCK);
else
else
{
p_etat->lap = p_etat->sts.tv_sec * NUM_FACTEUR + (p_etat->sts.tv_nsec / 10000);
param1->num = p_etat->lap - p_etat->start;
p_etat->start = p_etat->lap; // permet de refaire un appel de lapChrono
if(paramDuration->type != VAR_NUMBER)
var_let(e, paramDuration, &e->int_number, FALSE, FALSE);
/* */
exc = setError(p_etat, getChrono(e, &p_etat->ctx, &paramDuration->num));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setUTC", 6))
else if(modFnIs(e, "setNow", 6))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
/* get param in the right order */
var * paramHashTime = getParam(e, "timeParameterSet", 16);
if(paramHashTime != NULL)
{
// param2 = format ; param3 = date
if( ! MajTm(p_etat, param2->mPtr, param3->mPtr))
exc = EXMOD_FORMAT_KO;
if(paramHashTime->type == VAR_HASHTABLE)
exc = setError(p_etat, setNow(e, &p_etat->ctx, paramHashTime));
else
{
p_etat->dhm = MkTimeTU(p_etat);
p_etat->decalageHoraire = 0;
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
// param2 = format ; param3 = date
if(!MajTm(p_etat, param2->mPtr, param3->mPtr))
exc = EXMOD_FORMAT_KO;
else
{
p_etat->dhm = MkTimeTU(p_etat);
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
p_etat->dhm -= p_etat->decalageHoraire;
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setNowLocal", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
p_etat->dhm = time(NULL);
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setNowUTC", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
p_etat->dhm = time(NULL);
p_etat->decalageHoraire = 0;
// maj param1avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
/* get param in the right order */
var * paramHashTime = getParam(e, "timeParameterSet", 16);
var * paramTimestamp = getParam(e, "timestamp", 9);
var * paramOffset = getParam(e, "offset", 6);
var * paramString = getParam(e, "string", 6);
var * paramStringFormat = getParam(e, "stringFormat", 12);
/*
seules certaines combinaisons sont prises en charge :
1/ timestamp (UTC), timestamp (local) + offset
2/ string (format ISO8601 fixe A-M-JTh:m:SF), string + stringFormat
timeParameterSet obligatoire dans tous les cas
*/
if(paramHashTime != NULL && paramTimestamp != NULL)
{
// param2 = format ; param3 = date
if( ! MajTm(p_etat, param2->mPtr, param3->mPtr))
exc = EXMOD_FORMAT_KO;
number ntime, noff = NUM_ZERO;
if( ! var_conv_num(e, paramTimestamp, &ntime) || paramString != NULL || paramStringFormat != NULL)
exc = EX_MODPARAM;
else
{
p_etat->dhm = MkTimeTU(p_etat);
if(p_etat->decalageHoraire == HORODATE_DECALAGEHORAIREINCONNU)
exc = EXMOD_JETLAG_KO;
else
{
p_etat->dhm -= p_etat->decalageHoraire;
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
if(paramOffset != NULL)
if( ! var_conv_num(e, paramOffset, &noff))
exc = EX_MODPARAM;
if(exc == OK)
exc = setError(p_etat, setFromTimestamp(e, &p_etat->ctx, paramHashTime, (time_t)(ntime / NUM_FACTEUR), (long)(noff / NUM_FACTEUR)));
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getUTC", 6))
{
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 || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
else if(paramHashTime != NULL && paramString != NULL)
{
p_etat->decalageHoraire = 0;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->dhm = (p_etat->pv)->num / NUM_FACTEUR;
//
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
// resultat
dynLet(e, param3, p_etat->horodate.mPtr, DYN_LGNONE);
if(paramString->type != VAR_DYNAMIC || paramTimestamp != NULL || paramOffset != NULL)
exc = EX_MODPARAM;
else
{
if(paramStringFormat != NULL)
if(paramStringFormat->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
if(exc == OK)
exc = setError(p_etat, setFromString(e, &p_etat->ctx, paramHashTime, paramString, paramStringFormat ? paramStringFormat->mPtr : TIMESTAMP_ISO8601));
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
hashtable_do(e, HASH_READ, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->dhm = (p_etat->pv)->num / NUM_FACTEUR;
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
//
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
// resultat
dynLet(e, param3, p_etat->horodate.mPtr, DYN_LGNONE);
}
exc = EX_MODPARAM;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
/* get param in the right order */
var * paramHashTime = getParam(e, "timeParameterSet", 16);
var * paramFormat = getParam(e, "timedateFormat", 14);
var * paramUTC = getParam(e, "timedateUTC", 11);
var * paramResult = getParam(e, "timedateString", 14);
if(paramHashTime != NULL && paramFormat != NULL && paramUTC != NULL && paramResult != NULL)
{
hashtable_do(e, HASH_READ, param1, copy_nom(e, "jetlag"), &p_etat->pv);
p_etat->decalageHoraire = (p_etat->pv)->num / NUM_FACTEUR;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->dhm = (p_etat->pv)->num / NUM_FACTEUR;
//
if(p_etat->decalageHoraire == HORODATE_DECALAGEHORAIREINCONNU)
p_etat->decalageHoraire = 0; // securite : se remettre en UTC
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
// resultat
dynLet(e, param3, p_etat->horodate.mPtr, DYN_LGNONE);
number utc;
if(var_conv_num(e, paramUTC, &utc) && paramHashTime->type == VAR_HASHTABLE && paramFormat->type == VAR_DYNAMIC)
{
if(paramResult->type != VAR_DYNAMIC)
var_let(e, paramResult, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramResult, 0);
/* */
exc = setError(p_etat, getTimeDate(e, &p_etat->ctx, paramHashTime, paramResult, paramFormat->mLg == 0 ? TIMESTAMP_ISO8601 : paramFormat->mPtr, (int)(utc != 0)));
}
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "alarmUTCHM", 10))
else if(modFnIs(e, "setAlarm", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramBegin = getParam(e, "beginning", 4);
var * paramDelay = getParam(e, "delay", 4);
var * paramGmt = getParam(e, "gmt", 3);
var * paramOcc = getParam(e, "occurence", 9);
if(paramName == NULL || paramBegin == NULL || paramDelay == NULL || paramGmt == NULL || paramOcc == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC || paramBegin->type != VAR_DYNAMIC || paramDelay->type != VAR_DYNAMIC ||
(paramGmt->type != VAR_DYNAMIC && paramGmt->type != VAR_NUMBER) || (paramOcc->type != VAR_DYNAMIC && paramOcc->type != VAR_NUMBER))
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
// TODO a tester
ent64s hhmm = param1->num / NUM_FACTEUR;
// param2 = alarme_tfin (sortie) ; param3 = m_Tmp ~ delai (sortie)
long now,alarme_tfin;
now = time(NULL);
p_etat->decalageHoraire = 0;
p_etat->dhm = now;
FormatTm(e, p_etat, HORODATE_ISO8601, p_etat->dhm, p_etat->decalageHoraire);
sprintf(p_etat->horodate.mPtr + 11, "%02lld", hhmm / 100);
p_etat->horodate.mPtr[13] = ':';
sprintf(p_etat->horodate.mPtr + 14, "%02lld", hhmm % 100);
p_etat->horodate.mPtr[16] = ':';
p_etat->horodate.mPtr[17] = '0';
p_etat->horodate.mPtr[18] = '0';
//
if( ! MajTm(p_etat, HORODATE_ISO8601, p_etat->horodate.mPtr))
exc = EXMOD_FORMAT_KO;
else
number ngmt, nocc;
if(var_conv_num(e, paramGmt, &ngmt) && var_conv_num(e, paramOcc, &nocc))
{
alarme_tfin = p_etat->dhm;
if(alarme_tfin < now)
alarme_tfin += 86400;
dynLet(e, param2, Int64ToSz(e, alarme_tfin, FALSE, 19), DYN_LGNONE);
dynLet(e, param3, "86400", 5); // delai
exc = setError(p_etat, activateAlarm(e, &p_etat->ctx, paramName, paramBegin, (int)(ngmt != 0), paramDelay, (int)(nocc / NUM_FACTEUR)));
}
else
exc = setError(p_etat, EX_MODPARAM);
}
}
else if(modFnIs(e, "stopAlarm", 9))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
if(paramName == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, stopAlarm(e, &p_etat->ctx, paramName));
}
}
else if(modFnIs(e, "getNextActivation", 17))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramNext = getParam(e, "nextTime", 8);
if(paramName == NULL || paramNext == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC || paramNext->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, getNextActivation(e, &p_etat->ctx, paramName, paramNext));
}
}
else if(modFnIs(e, "alarmActive", 11))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramActive = getParam(e, "isActive", 8);
if(paramName == NULL || paramActive == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramActive->type != VAR_NUMBER)
var_let(e, paramActive, &e->int_number, FALSE, FALSE);
paramActive->num = 0;
exc = setError(p_etat, getAlarmActive(e, &p_etat->ctx, paramName, &paramActive->num));
}
}
else if(modFnIs(e, "triggeredAlarm", 14))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramTriggered = getParam(e, "triggered", 9);
var * paramReposition = getParam(e, "reposition", 10); /* optionnel, par defaut @true = 1 : se recaler */
if(paramName == NULL || paramTriggered == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
int repos = 1;
if(paramReposition != NULL)
{
if(paramReposition->type != VAR_DYNAMIC && paramReposition->type != VAR_NUMBER)
exc = EX_MODPARAM;
else if( ! var_conv_num(e, paramReposition, &e->int_number.num))
exc = EX_MODPARAM;
else
repos = (int)(e->int_number.num != 0);
}
/* */
if(exc == OK)
{
if(paramTriggered->type != VAR_NUMBER)
var_let(e, paramTriggered, &e->int_number, FALSE, FALSE);
/* */
paramTriggered->num = 0;
exc = setError(p_etat, alarmHasTriggered(e, &p_etat->ctx, paramName, repos, &paramTriggered->num));
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "alarmLocalHM", 12))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
// TODO prendre la version debuggee + a tester
ent64s hhmm = param1->num / NUM_FACTEUR;
// param2 = alarme_tfin (sortie) ; param3 = m_Tmp ~ delai (sortie)
long alarme_tfin, now;
now = time(NULL);
p_etat->dhm = now;
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
//
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
sprintf(p_etat->horodate.mPtr + 11, "%02lld", hhmm / 100);
p_etat->horodate.mPtr[13] = ':';
sprintf(p_etat->horodate.mPtr + 14, "%02lld", hhmm % 100);
p_etat->horodate.mPtr[16] = ':';
p_etat->horodate.mPtr[17] = '0';
p_etat->horodate.mPtr[18] = '0';
//
if( ! MajTm(p_etat, HORODATE_ISO8601, p_etat->horodate.mPtr))
exc = EXMOD_FORMAT_KO;
else
{
alarme_tfin = p_etat->dhm;
if(alarme_tfin < now)
{
// ajouter un jour sur le format "externe" ISO8601, idem quand echue pour calcul suivant
AddOneDay(e, p_etat);
// TODO : convertir les 2 lignes a suivre
if( ! MajTm(p_etat, HORODATE_ISO8601, p_etat->horodate.mPtr))
exc = EXMOD_FORMAT_KO;
else
{
p_etat->dhm = MkTimeTU(p_etat);
if(p_etat->decalageHoraire == HORODATE_DECALAGEHORAIREINCONNU)
exc = EXMOD_JETLAG_KO;
else
{
p_etat->dhm -= p_etat->decalageHoraire;
alarme_tfin = p_etat->dhm;
dynLet(e, param2, Int64ToSz(e, alarme_tfin, FALSE, 19), DYN_LGNONE);
dynLet(e, param3, p_etat->horodate.mPtr, 5); // delai
}
}
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+671
View File
@@ -0,0 +1,671 @@
/* **********************************************
__ __ __
\ \/ \/ / 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/>.
********************************************** */
#ifdef WINLIB
#include "windows.h"
#endif
#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 "time.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
#define TIME_DHM "dhm"
#define TIME_OFFSET "offset"
#define TIME_TM_TU "stm"
#define TIME_TM_LOCAL "stmLocal"
#define ALARM_NB_OCC "nbocc"
#define ALARM_DELAY "delay"
#define ALARM_DELAYGMT "gmt"
enum {
ALARM_STOP = -1 /* value of "nbocc" field */
};
/* ***** PRIVATE *************** */
static int clockGettimeMonotonic(modContextTime * ctx)
{
#ifdef UNIX
return clock_gettime(CLOCK_MONOTONIC, &ctx->sts);
#else
/* cf stackoverflow */
static LARGE_INTEGER ticksPerSec;
LARGE_INTEGER ticks;
if (!ticksPerSec.QuadPart)
{
QueryPerformanceFrequency(&ticksPerSec);
if(!ticksPerSec.QuadPart)
return -1; /* compatible Unix version */
}
QueryPerformanceCounter(&ticks);
ctx->sts.tv_sec = (long)(ticks.QuadPart / ticksPerSec.QuadPart);
ctx->sts.tv_nsec = (long)(((ticks.QuadPart % ticksPerSec.QuadPart) * 1000000000) / ticksPerSec.QuadPart);
return OK; /* compatible Unix version */
#endif
}
static var * checkAndCreateHashtableItemNumber(env * e, var * hash, const char * name, number defaut)
{
if(strlen(name) > 24)
return NULL;
var * v;
hashtable_do(e, HASH_READ, hash, copy_nom(e, name), &v);
if(!v)
{
v = &e->int_number;
v->num = defaut;
/* */
v = hashtable_writeinfirstfreeentry(e, hash, copy_nom(e, name), v);
}
return v;
}
static var * checkAndCreateHashtableItemDynamic(env * e, var * hash, const char * name, int defaut, int size)
{
if(strlen(name) > 24)
return NULL;
var * v;
hashtable_do(e, HASH_READ, hash, copy_nom(e, name), &v);
if(!v)
{
v = &e->int_dynamic;
var_resize(e, v, size, 0);
if(e->exception != OK)
{
e->exception = OK;
return NULL;
}
/* */
v = hashtable_writeinfirstfreeentry(e, hash, copy_nom(e, name), v);
memset(v->ptr, defaut, size);
}
return v;
}
static int checkHashTime(env * e, modContextTime * ctx, var * hashTime)
{
var * v;
if(!(ctx->dhm = checkAndCreateHashtableItemNumber(e, hashTime, TIME_DHM, (number)0)))
return FALSE;
if(!(ctx->offset = checkAndCreateHashtableItemNumber(e, hashTime, TIME_OFFSET, TIMESTAMP_OFFSET_UNKNOWN)))
return FALSE;
if(!(v = checkAndCreateHashtableItemDynamic(e, hashTime, TIME_TM_TU, 0, sizeof(struct tm))))
return FALSE;
ctx->stm = (struct tm *)(v->ptr);
if(!(v = checkAndCreateHashtableItemDynamic(e, hashTime, TIME_TM_LOCAL, 0, sizeof(struct tm))))
return FALSE;
ctx->stmLocal = (struct tm *)(v->ptr);
/* */
return TRUE;
}
static int checkHashAlarm(env * e, modContextTime * ctx, var * hash)
{
if( ! checkHashTime(e, ctx, hash)) /* next activation */
return FALSE;
if(!(ctx->delay = checkAndCreateHashtableItemNumber(e, hash, ALARM_DELAY, (number)0)))
return FALSE;
if(!(ctx->gmt = checkAndCreateHashtableItemNumber(e, hash, ALARM_DELAYGMT, (number)1)))
return FALSE;
if(!(ctx->nbocc = checkAndCreateHashtableItemNumber(e, hash, ALARM_NB_OCC, ALARM_STOP)))
return FALSE;
/* */
return TRUE;
}
static int checkAlarmName(env * e, var * name)
{
if(!name)
return FALSE;
if(name->type != VAR_DYNAMIC)
return FALSE;
if(name->mLg < 1 || name->mLg > 24)
return FALSE;
/* */
char c = name->mPtr[0];
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
{
for(int i = 1; i < name->mLg; i++)
{
c = name->mPtr[i];
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
continue;
else
return FALSE;
}
return TRUE;
}
else
return FALSE;
}
static var * getHashAlarm(env * e, modContextTime * ctx, var * name)
{
if( ! checkAlarmName(e, name))
return NULL;
var * hash;
hashtable_do(e, HASH_READ, &ctx->alarmList, name->mPtr, &hash);
if(hash)
if(hash->type != VAR_HASHTABLE)
hash = NULL; /* securite */
return hash;
}
static int isDigit(char ** p, int n, int * val)
{
char c;
*val = 0;
while(n--)
{
c = **p;
(*p)++;
if(c < '0' || c > '9')
return FALSE;
*val = *val * 10 + (c - '0');
}
return TRUE;
}
static void setFromStm(env * e, modContextTime * ctxTime, var * hashTime, int utc)
{
struct tm stm = *ctxTime->stm;
stm.tm_isdst = -1;
ctxTime->dhm->num = mktime(&stm); /* mktime assume que stm est en local */
/* et donc se remettre en TU si demande */
if(utc)
ctxTime->dhm->num += 3600 * (stm.tm_isdst + 1);
setFromTimestamp(e, ctxTime, hashTime, ctxTime->dhm->num, 0);
}
void timeDebug(env * e, modContextTime * ctxTime, var * hashTime)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return;
/* */
printf("-----------------\n");
printf("struct tm (TU) : %04d/%02d/%02d %02d:%02d:%02d\n", ctxTime->stm->tm_year + 1900, ctxTime->stm->tm_mon + 1, ctxTime->stm->tm_mday, ctxTime->stm->tm_hour, ctxTime->stm->tm_min, ctxTime->stm->tm_sec);
printf("struct tmLocal : %04d/%02d/%02d %02d:%02d:%02d\n", ctxTime->stmLocal->tm_year + 1900, ctxTime->stmLocal->tm_mon + 1, ctxTime->stmLocal->tm_mday, ctxTime->stmLocal->tm_hour, ctxTime->stmLocal->tm_min, ctxTime->stmLocal->tm_sec);
printf("time_t dhm : %lld\n", ctxTime->dhm->num);
printf("decalage offset: %lld\n", ctxTime->offset->num);
time_t t = (time_t)(ctxTime->dhm->num - ctxTime->offset->num); /* ctime() renvoi le format "local"... */
printf("ctime dhm : %s", ctime(&t));
t = (time_t)(ctxTime->dhm->num);
printf("ctime dhm + off: %s", ctime(&t));
printf("-----------------\n");
}
void alarmDebug(env * e, modContextTime * ctxTime)
{
//
var * v = &e->int_hash;
var * vn = &e->int_number;
hashtable_select(e, &ctxTime->alarmList);
while(hashtable_next(e, &ctxTime->alarmList, e->tmp_dynamic.mPtr, &v))
{
printf("==================\n");
printf("alarm name : %s\n", e->tmp_dynamic.mPtr);
hashtable_do(e, HASH_READ, v, copy_nom(e, ALARM_DELAY), &vn);
if(vn) printf("alarm delay : %lld\n", vn->num);
hashtable_do(e, HASH_READ, v, copy_nom(e, ALARM_DELAYGMT), &vn);
if(vn) printf("alarm gmt : %lld\n", vn->num);
hashtable_do(e, HASH_READ, v, copy_nom(e, ALARM_NB_OCC), &vn);
if(vn) printf("alarm occur. : %lld\n", vn->num);
/* next activation */
timeDebug(e, ctxTime, v);
}
}
/* *********************************************************************************************************** */
/* ***** PUBLIC *************** */
WAPIDECL void initTime(env * e, modContextTime * ctx)
{
ctx->start = NUM_ZERO;
ctx->lap = NUM_ZERO;
var_init(e, &ctx->alarmList, VAR_HASHTABLE, 3, 8, NULL);
}
WAPIDECL void freeTime(env * e, modContextTime * ctx)
{
var_free(e, &ctx->alarmList, TRUE);
}
/* for Chrono methods */
WAPIDECL long startChrono(env * e, modContextTime * ctx)
{
if (clockGettimeMonotonic(ctx) != OK)
return EXMOD_GETCLOCK;
else
{
ctx->start = ctx->sts.tv_sec * NUM_FACTEUR + (ctx->sts.tv_nsec / 10000);
return OK;
}
}
WAPIDECL long getChrono(env * e, modContextTime * ctx, number * duration)
{
if (clockGettimeMonotonic(ctx) != OK)
return EXMOD_GETCLOCK;
else
{
ctx->lap = ctx->sts.tv_sec * NUM_FACTEUR + (ctx->sts.tv_nsec / 10000);
*duration = ctx->lap - ctx->start;
ctx->start = ctx->lap; // permet de refaire un appel de lapChrono
return OK;
}
}
/* for time and date =>
Permet de stocker une horodate en masquant les complications liees aux bibliotheques standards C :
. mettre une horodate dans l'objet en utilisant une des methodes "set"
. recuperer l'horodate selon le format voulu en utilisant une des methodes "get"
hash.dhm, hash.offset : number (binaire)
hash.stm, hash.stmLocal : dynamic (mode "binaire")
*/
WAPIDECL int setNow(env * e, modContextTime * ctxTime, var * hashTime)
{
return setFromTimestamp(e, ctxTime, hashTime, time(NULL), 0);
}
WAPIDECL int setFromTimestamp(env * e, modContextTime * ctxTime, var * hashTime, time_t dhm, long offset)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return EXMOD_TIMEDATE_CONTEXT_KO;
/* */
/* offset donne le decalage horaire de dhm, dhm exprime en local (0 si UTC, cas de time(NULL) ) */
ctxTime->dhm->num = dhm - offset; // se remettre en TU
// calcul decalage horaire local
ctxTime->stm->tm_isdst = -1;
ctxTime->stmLocal->tm_isdst = -1;
time_t t = (time_t)(ctxTime->dhm->num);
*ctxTime->stmLocal = *localtime(&t);
*ctxTime->stm = *gmtime(&t);
/* */
struct tm stml = *ctxTime->stmLocal;
struct tm stmg = *ctxTime->stm;
ctxTime->offset->num = ctxTime->stmLocal->tm_isdst == 1 ? 3600 : 0; /* heure ete/hiver */
ctxTime->offset->num += mktime(&stml) - mktime(&stmg); /* modifie les struct tm ! donc utiliser des vars tempo */
//ctxTime->dhm->num -= ctxTime->offset->num; // a enlever car dhm en local (si en UTC, offset doit etre passe a 0, donc c'est pareil que toujours en local)
return OK;
}
/*
Formatage d'une Horodate :
A Y : annee sur 4 chiffres
a y : annee sur 2 chiffres ( 0 => 2000 )
M : mois sur 2 chiffres
L : mois sur 3 lettres (RFC822/5322) Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
J D : jour sur 2 chiffres
l : jour de la semaine sur 3 lettres (RFC822/5322) Mon Tue Wed Thu Fri Sat Sun
h : heure sur 2 chiffres
m : minutes sur 2 chiffres
S : secondes sur 2 chiffres avec les fractions de secondes (de 0 a 7 decimales), exemple "12,456" ou "01.1234567" (les fractions de secondes sont ignorees et ne sont pas memorisees)
s : secondes sur 2 chiffres
F : fuseau horaire, soit "Z" pour UTC, soit "+/-mm:ss" heures et minutes en plus ou moins, exemples "+01:00" "-02:30" etc.
f : zone (RFC822/5322) UT GMT EST EDT CST CDT MST MDT PST PDT
0 0 -5 -4 -6 -5 -7 -6 -8 -7
g : zone (RFC822/1522 militaire) (1,1,a-ik-zA-IK-Z) ; A à M : -1 à -12 ; N à Y : +1 à +12 ; Z = UTC
n : zone numerique (1,1,+-) (4,4,0-9) : +0000 pour UTC, +0200, -0100, etc.
*/
WAPIDECL int setFromString(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return EXMOD_TIMEDATE_CONTEXT_KO;
/* */
memset(ctxTime->stm, 0, sizeof(struct tm));
memset(ctxTime->stmLocal, 0, sizeof(struct tm));
ctxTime->dhm->num = 0;
ctxTime->offset->num = TIMESTAMP_OFFSET_UNKNOWN;
/* */
struct tm stm = {0};
stm.tm_isdst = -1;
/* */
char * d = dhm->mPtr, * f = (char *)format, fc;
int value;
for(;;)
{
if((fc = *f++) == 0) break;
/* */
if(fc == 'A' || fc == 'Y')
{
if( ! isDigit(&d, 4, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_year = value - 1900;
}
else if(fc == 'a' || fc == 'y')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_year = value + 100; /* pas d'annee avant 2000 => mettre une annee pivot du style si < 50, 20xx sinon 19xx ? */
}
else if(fc == 'M')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_mon = value - 1; /* mois de 0 a 11 */
}
else if(fc == 'J' || fc == 'D')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_mday = value; /* jour de 1 a 31 */
}
else if(fc == 'h')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_hour = value; /* heure de 0 a 23 */
}
else if(fc == 'm')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_min = value; /* minutes de 0 a 59 */
}
else if(fc == 's')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_sec = value; /* secondes de 0 a 59 */
}
else if(fc == 'S')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_sec = value; /* secondes de 0 a 59 */
/* tester 7 decimales (pas d'erreur si non present) */
if(*d == ',' || *d == '.')
{
d++;
for(int ndec = 1; ndec <= 7; ndec++, d++)
if(*d < '0' || *d > '9')
break;
}
}
else if(fc == 'F')
{
if(*d == 'Z')
{
ctxTime->offset->num = 0;
d++;
}
else if(*d == '+' || *d == '-')
{
int signe = (*d++ == '-') ? -1 : 1;
if( ! isDigit(&d, 2, &value))
return EXMOD_TIMEDATE_STRING_KO;
ctxTime->offset->num = signe * value * 3600; // decalage en secondes
if(*d++ != ':')
return EXMOD_TIMEDATE_STRING_KO;
if( ! isDigit(&d, 2, &value))
return EXMOD_TIMEDATE_STRING_KO;
ctxTime->offset->num += signe * value * 60; // decalage en secondes
}
else
return EXMOD_TIMEDATE_STRING_KO; // erreur : le format ne correspond pas a la chaine d'entree
}
else
{
if(*d++ != fc) return EXMOD_TIMEDATE_STRING_KO; // erreur : le format ne correspond pas a la chaine d'entree
}
}
if(*d != 0)
return EXMOD_TIMEDATE_STRING_KO; // fin de "format" mais pas en fin de chaine en entree "dhm"
/* maj struct stm et stmLocal */
ctxTime->dhm->num = mktime(&stm); /* mktime assume que stm est en local */
/* si fuseau horaire absent, local pris en compte par defaut */
if(ctxTime->offset->num == 0)
ctxTime->dhm->num += 3600 * (stm.tm_isdst + 1); /* stm en UTC : corriger */
setFromTimestamp(e, ctxTime, hashTime, ctxTime->dhm->num, 0); /* toujours en UTC ici */
/* */
return OK;
}
WAPIDECL int getTimeDate(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format, int wantUTC)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return EXMOD_TIMEDATE_CONTEXT_KO;
/* */
struct tm stm;
stm = (wantUTC ? *ctxTime->stm : *ctxTime->stmLocal);
/* */
char months[48] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0";
char days[28] = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0";
/* */
char * f = (char *)format, fc, fs[2] = {0};
for(;;)
{
if((fc = *f++) == 0) break;
/* */
if(fc == 'Y' || fc == 'A')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_year + 1900, FALSE, 4), 4);
}
else if(fc == 'y' || fc == 'a')
{
dynConcatSz(e, dhm, Int32ToSz((stm.tm_year + 1900) % 100, FALSE, 2), 2);
}
else if(fc == 'M')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_mon + 1, FALSE, 2), 2);
}
else if(fc == 'L')
{
if(stm.tm_mon >= 0 && stm.tm_mon <= 11)
dynConcatSz(e, dhm, months + stm.tm_mon * 4, 3);
}
else if(fc == 'J' || fc == 'D')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_mday, FALSE, 2), 2);
}
else if(fc == 'l')
{
if(stm.tm_wday >= 0 && stm.tm_wday <= 6)
dynConcatSz(e, dhm, days + stm.tm_wday * 4, 3);
}
else if(fc == 'h')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_hour, FALSE, 2), 2);
}
else if(fc == 'm')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_min, FALSE, 2), 2);
}
else if(fc == 's' || fc == 'S')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_sec, FALSE, 2), 2);
}
else if(fc == 'F')
{
if(wantUTC)
dynConcatSz(e, dhm, "Z", 1);
else
{
dynConcatSz(e, dhm, (ctxTime->offset < 0) ? "-" : "+", 1);
dynConcatSz(e, dhm, Int32ToSz(abs(ctxTime->offset->num) / 3600, FALSE, 2), 2);
dynConcatSz(e, dhm, ":", 1);
dynConcatSz(e, dhm, Int32ToSz((abs(ctxTime->offset->num) % 3600) / 60, FALSE, 2), 2);
}
}
else
{
fs[0] = fc;
dynConcatSz(e, dhm, fs, 1);
}
}
return OK;
}
/* for alarms */
WAPIDECL int activateAlarm(env * e, modContextTime * ctxTime, var * name, var * heureDebut, int utc, var * delaiSeconde, int occurences)
{
if( ! checkAlarmName(e, name))
return EXMOD_ALARM_CONTEXT_KO;
if(!heureDebut || !delaiSeconde)
return EXMOD_ALARM_CONTEXT_KO;
if(heureDebut->type != VAR_DYNAMIC || delaiSeconde->type != VAR_DYNAMIC) /* format hh:mm:ss */
return EXMOD_ALARM_CONTEXT_KO;
/*
differents type de gestion :
- a partir de l'heure courante, declencher l'alarme toutes les x secondes, avec un nombre d'occurences limite ou non
- déclenchement à une heure fixe, avec un délai ou non : toutes les heures pleines, toutes les heures et 23 minutes, délai de 1j, 1h, 15 mn, etc. et avec un nombre d'occurences limité ou non
=> donc, parametre heure de debut en TU ou en local, délai entre chaque alarme (TU ou local idem debut) et nombre d'occurence. heure debut <vide> = tout de suite, nb occurence 0 = tout le temps
heureDebut et delaiSecondes en format "externe" hh:mm:ss (converti en secondes en interne dans delay, attention au chgt d'heure !), en tu = 1 oui, 0 en local
alarmList : hashtable, contenant les alarmes, chacune etant une autre hastable
alarmList!name: hashtable
alarmList!name.dhm .offset : number(binaire), prochaine echeance
alarmList!name.stm .stmLocal : dynamic (mode "binaire"), prochaine echeance
alarmList!name.delay .nbocc .gmt: number, delay en secondes, gmt flag 0/1 si delay sur la base du TU (1) ou du Local (0)
*/
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
{
/* creer l'alarme (uniquement lors de l'activation, si besoin) */
hash = &e->int_hash;
e->int_hash.type = VAR_HASHTABLE;
var_resize(e, hash, 3, 8);
if(e->exception != OK)
{
e->exception = OK;
return EXMOD_ALARM_CONTEXT_KO;
}
hashtable_do(e, HASH_WRITE, &ctxTime->alarmList, name->mPtr, &hash);
hash = hashtable_lastitemwritten(&ctxTime->alarmList); /* car HASH_WRITE fait une copie */
}
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* */
number h,m,s, d;
h = dynFieldAsNumber(e, heureDebut, 1, DYN_NONE, ':', DYN_NONE);
m = dynFieldAsNumber(e, heureDebut, 2, DYN_NONE, ':', DYN_NONE);
s = dynFieldAsNumber(e, heureDebut, 3, DYN_NONE, ':', DYN_NONE);
d = dynFieldAsNumber(e, delaiSeconde, 1, DYN_NONE, ':', DYN_NONE) * 3600 + dynFieldAsNumber(e, delaiSeconde, 2, DYN_NONE, ':', DYN_NONE) * 60 + dynFieldAsNumber(e, delaiSeconde, 3, DYN_NONE, ':', DYN_NONE);
/* */
ctxTime->gmt->num = (number)utc;
ctxTime->nbocc->num = (number)occurences;
ctxTime->delay->num = d;
/* */
setNow(e, ctxTime, hash);
if(heureDebut->mLg > 0)
{
/* ajuster le demarrage */
ctxTime->stm->tm_hour = h;
ctxTime->stm->tm_min = m;
ctxTime->stm->tm_sec = s;
setFromStm(e, ctxTime, hash, utc);
}
else
ctxTime->dhm->num += ctxTime->delay->num;
/* */
/* calculate next activation */
while(ctxTime->dhm->num < time(NULL))
ctxTime->dhm->num += ctxTime->delay->num;
setFromTimestamp(e, ctxTime, hash, ctxTime->dhm->num, 0); /* toujours en UTC ici */
/* heure locale pour prochaine activation (idem triggered) ?? */
return OK;
}
WAPIDECL int getNextActivation(env * e, modContextTime * ctxTime, var * name, var * hashTime)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* */
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_DHM), &ctxTime->dhm);
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_OFFSET), &ctxTime->offset);
var * v = &e->int_dynamic;
v->mLg = sizeof(struct tm);
memcpy(e->int_dynamic.mPtr, ctxTime->stm, v->mLg);
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_TM_TU), &v);
memcpy(e->int_dynamic.mPtr, ctxTime->stmLocal, v->mLg);
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_TM_LOCAL), &v);
return OK;
}
WAPIDECL int getAlarmActive(env * e, modContextTime * ctxTime, var * name, number * active)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect : RAS */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* active si pas stoppee */
*active = (ctxTime->nbocc->num != ALARM_STOP) ? NUM_UN : NUM_ZERO;
return OK;
}
WAPIDECL int stopAlarm(env * e, modContextTime * ctxTime, var * name)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect : RAS */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* pour stopper : nbocc mis a -1 */
ctxTime->nbocc->num = ALARM_STOP;
return OK;
}
WAPIDECL int alarmHasTriggered(env * e, modContextTime * ctxTime, var * name, number reposition, number * triggered)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect : idem pas echue */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* */
*triggered = NUM_ZERO;
/* en temps/duree GMT (TU) suffit ici */
if(ctxTime->nbocc->num > ALARM_STOP && ctxTime->dhm->num <= time(NULL))
{
/* alarm has triggered, calculate next activation */
*triggered = NUM_UN;
/* */
ctxTime->dhm->num += ctxTime->delay->num;
while(reposition && ctxTime->dhm->num < time(NULL))
ctxTime->dhm->num += ctxTime->delay->num;
setFromTimestamp(e, ctxTime, hash, ctxTime->dhm->num, 0); /* toujours en UTC ici */
/* calcul prochaine activation selon heure locale ?? */
/* */
if(ctxTime->nbocc->num > 0)
if( (--ctxTime->nbocc->num) == 0)
ctxTime->nbocc->num = ALARM_STOP;
}
return OK;
}
+152 -91
View File
@@ -111,96 +111,104 @@ WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm
}
}
WAPIDECL int varptrtbl_ctrl(env * e, var * v)
{
/* 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 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;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v->ptr)
return TRUE; // deja existant
else
curr += 2;
// pas trouve
return FALSE;
}
WAPIDECL void varptrtbl_add(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 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 addnb = nb + 1;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v->ptr)
return; // deja existant : RAS
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;
*curr = (pointeur)v->ptr;
}
}
WAPIDECL void varptrtbl_del(env * e, var * v)
{
// supprime de e->varptrtbl la var 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->ptr)
{
// 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
}
// obsolete
//WAPIDECL int varptrtbl_ctrl(env * e, var * v)
//{
// /* 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;
//}
//
//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)
if(v == NULL || num == NULL)
return FALSE;
if(v->type == VAR_PARAM)
v = (var *)v->ptr;
{
if((v = (var *)v->ptr) == NULL)
return FALSE;
}
if(v->type == VAR_NUMBER)
{
*num = v->num;
@@ -220,7 +228,13 @@ WAPIDECL void var_free(env * e, var * v, int suivre_par)
if(v == NULL)
return;
if(suivre_par && v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* rien a liberer sur vars NULL, NUMBER et PARAM (ce dernier cas n'est pas possible) */
switch(v->type)
{
@@ -255,13 +269,25 @@ 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 */
/* ici correspondont a "let = v" */
/* ici correspond a "let = v" */
if(suivre_let && let->type == VAR_PARAM)
let = (var *)let->ptr; /* travailler avec la var pointee ! */
{
if((let = (var *)let->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
if(suivre_v && v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
// liberation variable affectee
var_free(e, let, TRUE);
var_free(e, let, FALSE); /* let pointe sur la vraie var si VAR_PARAM et suivre */
// init et copie
switch(v->type)
{
@@ -288,8 +314,11 @@ WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
break;
//
case VAR_PARAM:
if(!suivre_v)
if(!suivre_v) // ??
{
var_init(e, let, VAR_PARAM, 0, 0, v->ptr);
let->etat = v->etat;
}
break;
case VAR_BUFFER:
@@ -298,4 +327,36 @@ WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
}
}
WAPIDECL void var_resize(env * e, var * v, ent64 mod_lgm, ent64 sep)
{
if(v == NULL)
{
e->exception = EX_NAVAR;
return;
}
if(v->type == VAR_PARAM)
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* */
if(v->type == VAR_DYNAMIC)
{
if(dynResize(e, v, mod_lgm) != DYN_OK)
e->exception = EX_NAVAR; /* erreur de resize, prevoir une erreur specifique ? */
}
else if(v->type == VAR_HASHTABLE)
{
var_free(e, v, FALSE);
var_init(e, v, VAR_HASHTABLE, mod_lgm, sep, NULL);
if(v->type != VAR_HASHTABLE)
e->exception = EX_NAVAR; /* erreur de resize, prevoir une erreur specifique ? */
}
else
e->exception = EX_NAVAR; /* resize uniquement de dynamic et hashtable, prevoir une erreur specifique ? */
}
/* ********************************************** */
+2 -1
View File
@@ -29,9 +29,10 @@ WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm
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 void var_resize(env * e, var * v, ent64 mod_lgm, ent64 sep);
WAPIDECL int varptrtbl_ctrl(env * e, var * v);
WAPIDECL void varptrtbl_add(env * e, var * v);
WAPIDECL void varptrtbl_maj(env * e, var * v);
WAPIDECL void varptrtbl_del(env * e, var * v);
/* ********************************************** */
+5 -2
View File
@@ -51,7 +51,7 @@ input: input
declare: declare
let: let
delet: delet ; unlet ??
delet: delet
new: new
class: class
@@ -66,6 +66,8 @@ frac: frac
abs: abs
neg: neg
round: round
sqrt: sqrt
exp: exp
type: type
len: len
@@ -74,6 +76,7 @@ dcount: dcount
field: field
index: index
search: search
sortedsearch: sortedsearch
change: change
format: format
insert: insert
@@ -101,7 +104,7 @@ ends: (1,1,#5D) ; ]
indirect: !
typeof: ? ; typeof ??
typeof: typeof ; typeof x.y.z
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
+91
View File
@@ -0,0 +1,91 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "langage.h"
#include "dynamic.h"
// --- gestion protocole websocket (http + protocole binaire specifique)
typedef struct {
int state; /* etat de decodage des trames http/ws : 0 entete a lire, 1 en cours lecture entete, 2 lecture corps websocket binaire */
ent64s lengthToRead; /* longueur de donnees (corps, frame header) restant a lire */
Dynamic header; /* liste des entetes http <1,x> nom entete (minuscule) <2, x> valeur, le decodage de la premiere ligne est mis ici : http_method http_path http_vers */
Dynamic content; /* corps du message binaire ws */
Dynamic contentControl; /* content control frame found in fragment */
Dynamic line, tmp; /* buffer de lecture d'une ligne, variable de travail */
Dynamic frameHeader; /* 14 octets utilises maxi */
int finalFrame, mask, opcode, len, fragment, opcodeFragment, controlInFragment;
octet maskey[4];
int error;
} modCtxWs;
enum {
/* state */
WSSTATE_HEADERTOREAD = 0,
WSSTATE_READINGHEADER = 1,
WSSTATE_READINGFRAMEHEADER = 2,
WSSTATE_READINGFRAMEHEADEREXT = 3,
WSSTATE_READINGFRAMECONTENT = 4,
/* codes d'erreur */
WS_METHOD_KO = 1,
WS_METHOD_VERSION_KO = 2,
WS_INCORRECT_LENGTH = 3,
WS_COLON_MISSING = 4,
WS_MISSING_HEADER = 5,
WS_MISSING_MASK = 6,
WS_OPCODE_KO = 7,
WS_FRAGMENT_KO = 8,
WS_LENGTH_TOO_HIGH = 9,
WS_MEMORY = 10,
/* code retour */
WS_REQUEST_ERROR = -1,
WS_REQUEST_INPROGRESS = 0,
WS_REQUEST_COMPLETE = 1,
WS_REQUEST_EXPECTCONTENT = 2,
WS_REQUEST_CLOSE = 3,
WS_REQUEST_PING = 4,
WS_REQUEST_PONG = 5,
WS_REQUEST_FRAGMENT = 6,
/* framing opcode */
WS_FRAME_OPCODE_TEXT = 1,
WS_FRAME_OPCODE_BINARY = 2,
WS_FRAME_OPCODE_CLOSE = 8,
WS_FRAME_OPCODE_PING = 9,
WS_FRAME_OPCODE_PONG = 10,
/* framing fragment */
WS_FRAME_FRAGMENT_ON = 0,
WS_FRAME_FRAGMENT_OFF = 1,
WS_FRAME_MASK_ON = 1,
WS_FRAME_MASK_OFF = 0
};
WAPIDECL void Init(env * e, modCtxWs * ctx);
WAPIDECL void End(env * e, modCtxWs * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxWs * ctx, Dynamic * data);
WAPIDECL long MakeExpectContent(env * e, modCtxWs * ctx, Dynamic * reponse);
WAPIDECL long MakeFrame(env * e, modCtxWs * ctx, int frameType, Dynamic * data, Dynamic * response);
+475
View File
@@ -0,0 +1,475 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "websocket.h"
#include "convert.h"
#include "hash.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
#define CRLF "\r\n"
#define LEN_CRLF 2
static int HeaderCheck(env * e, modCtxWs * ctx, char * headerName, char * headerValue)
{
long posEntete = dynLocateSz(e, &ctx->header, headerName, cVM, 1, cFM);
if(posEntete == DYN_NOTLOCATED)
return FALSE;
/* */
dynField(e, &ctx->header, &ctx->tmp, 1, posEntete, cFM, cVM, 1);
if(headerValue)
{
str2lower(e, &ctx->tmp);
return dynCompare(e, &ctx->tmp, CMP_EQ, headerValue, DYN_LGNONE);
}
else
return TRUE;
}
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxWs * ctx)
{
ctx->error = 0;
ctx->state = WSSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
ctx->fragment = FALSE; /* TRUE if fragmentation is on */
ctx->controlInFragment = FALSE;
dynInit(e, &ctx->header, DYN_LGMIN);
dynInit(e, &ctx->content, DYN_LGMIN);
dynInit(e, &ctx->contentControl, DYN_LGMIN);
dynInit(e, &ctx->line, DYN_LGMIN);
dynInit(e, &ctx->tmp, DYN_LGMIN);
dynInit(e, &ctx->frameHeader, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxWs * ctx)
{
dynFree(e, &ctx->header);
dynFree(e, &ctx->content);
dynFree(e, &ctx->contentControl);
dynFree(e, &ctx->line);
dynFree(e, &ctx->tmp);
dynFree(e, &ctx->frameHeader);
}
WAPIDECL long ExtractMessage(env * e, modCtxWs * ctx, Dynamic * data)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
if(ctx->state == WSSTATE_HEADERTOREAD || ctx->state == WSSTATE_READINGHEADER)
{
for(;;)
{
long ind = dynIndexSz(e, data, CRLF, LEN_CRLF, 1);
if(ind < 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
dynSetLen(e, &ctx->line, 0);
if(ind > 0)
dynSubstr(e, data, &ctx->line, 0, ind, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, ind + LEN_CRLF);
/* ici <ctx->line> contient la ligne d'entete et <data> est a jour avec les donnees suivantes */
/* */
if(ctx->state == WSSTATE_HEADERTOREAD)
{
/* premiere ligne du protocole */
dynField(e, &ctx->line, &ctx->tmp, 1, DYN_NONE, ' ', DYN_NONE, 1); // method
if(dynCompare(e, &ctx->tmp, CMP_NE, "GET", 3))
{
ctx->error = WS_METHOD_KO; /* seule GET autorisee */
return WS_REQUEST_ERROR; /* quand erreur, l'appelant doit vider le "conteneur" de donnee !? */
}
dynSetLen(e, &ctx->header, 0); // vider le header
dynInsSz(e, &ctx->header, 1, 1, "http_method", 11, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 2, DYN_NONE, ' ', DYN_NONE, 1); // path
dynInsSz(e, &ctx->header, 1, 1, "http_path", 9, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 3, DYN_NONE, ' ', DYN_NONE, 1);
if(ctx->tmp.mLg == 0)
{
ctx->error = WS_METHOD_KO; /* seule GET autorisee et version doit etre presente */
return WS_REQUEST_ERROR;
}
else
{
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
}
/* */
ctx->state = WSSTATE_READINGHEADER;
}
else
{
/* entetes a lire */
if(ctx->line.mLg == 0)
{
/* fin des entetes / entete typique ws =>
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
*/
dynSetLen(e, &ctx->content, 0);
if( ! HeaderCheck(e, ctx, "upgrade", "websocket"))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "connection", "upgrade"))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "host", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "origin", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "sec-websocket-version", "13"))
{
/* ici renvoyer une reponse 400 avec la valeur acceptee du serveur pour la version */
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "sec-websocket-key", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
/* ctx->tmp contient la clé codée en Base64 : calcul a faire pour renvoi au client */
dynConcatSz(e, &ctx->tmp, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36);
encodageSha1(e, &ctx->tmp, &ctx->line); // resultat en hexa ascii
hex2str(e, &ctx->line, &ctx->tmp); // binaire, à encoder en Base64
str2base64(e, &ctx->tmp, &ctx->line);
/* ajouter l'entete de reponse */
dynInsSz(e, &ctx->line, 1, DYN_NONE, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept:",
DYN_LGNONE, ' ', DYN_NONE);
dynConcatSz(e, &ctx->line, "\r\n\r\n", 4); /* fin de reponse http */
/* */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->lengthToRead = 2;
dynSetLen(e, &ctx->frameHeader, 0);
return WS_REQUEST_EXPECTCONTENT; /* envoyer la reponse (handshake) et attendre le contenu ws specifique */
}
else
{
/* lecture de l'entete */
dynBegin(e, &ctx->line);
if(dynNext(e, &ctx->line, &ctx->tmp, ':') > -1)
{
dynCut(e, &ctx->line, ctx->line.mInternal + 1);
// nom entete en minuscule
dynErase(e, &ctx->tmp, " ");
str2lower(e, &ctx->tmp);
if(dynLocateSz(e, &ctx->header, ctx->tmp.mPtr, cVM, 1, cFM) != DYN_NOTLOCATED)
continue; // entete deja memorisee, ignorer le doublon
// valeur
dynTrimSpace(e, &ctx->line);
// tmp = nom entete, line = valeur entete
dynIns(e, &ctx->header, 1, 1, &ctx->tmp, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->line, cFM, cVM);
}
else
{
/* erreur de syntaxe dans l'entete */
ctx->error = WS_COLON_MISSING;
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
}
}
} /* endless for */
}
/* */
/* a partir d'ici, une erreur provoque le retour a l'attente d'une entete de frame, pas d'entete html */
if(ctx->state == WSSTATE_READINGFRAMEHEADER)
{
/* lecture d'une requete WS : frame header 2 octets */
if(data->mLg == 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->frameHeader, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees d'entete sont lues, decodage de la frame */
dynConcatSz(e, &ctx->frameHeader, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
/* gerer la fragmentation ici (finalFrame), 1,2 ok, 8,9,10 possible au milieu mais non fragmente */
ctx->finalFrame = (ctx->frameHeader.ptr[0] & 1);
ctx->opcode = (ctx->frameHeader.ptr[0] >> 4);
/* fragment management */
if( ! ctx->fragment)
{
dynSetLen(e, &ctx->content, 0);
if(ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
; /* ras pas de fragmentation */
else if(ctx->opcode != WS_FRAME_OPCODE_TEXT && ctx->opcode != WS_FRAME_OPCODE_BINARY)
{
/* fragment non autorisee sur control frame ou opcode inconnu */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_FRAGMENT_KO;
return WS_REQUEST_ERROR;
}
else
{
/* debut de fragment */
ctx->fragment = TRUE;
ctx->opcodeFragment = ctx->opcode;
}
}
else
{
/* fragmentation en cours */
if(ctx->opcode == 0)
{
/* ras fragment suite ou fin */
if(ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
ctx->fragment = FALSE;
ctx->opcode = ctx->opcodeFragment;
}
else
{
if((ctx->opcode == WS_FRAME_OPCODE_CLOSE || ctx->opcode == WS_FRAME_OPCODE_PING || ctx->opcode == WS_FRAME_OPCODE_PONG)
&& ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
{
/* control frame autorisee au milieu de fragment */
ctx->controlInFragment = TRUE;
dynSetLen(e, &ctx->contentControl, 0);
}
else
{
/* opcode incorrect suite fragment suivant */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_FRAGMENT_KO;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
}
}
/* */
ctx->mask = (ctx->frameHeader.ptr[1] & 1);
ctx->len = (ctx->frameHeader.ptr[1] >> 1);
if( ! ctx->mask)
{
/* erreur : le client doit masquer tous ses messages */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_MISSING_MASK;
ctx->controlInFragment = FALSE;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
if( ctx->opcode != WS_FRAME_OPCODE_TEXT && ctx->opcode != WS_FRAME_OPCODE_BINARY &&
ctx->opcode != WS_FRAME_OPCODE_CLOSE && ctx->opcode != WS_FRAME_OPCODE_PING && ctx->opcode != WS_FRAME_OPCODE_PONG)
{
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_OPCODE_KO; /* opcode inconnu/non pris en charge */
ctx->controlInFragment = FALSE;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
if(ctx->len < 126)
ctx->lengthToRead = 4; /* masking key */
else if(ctx->len == 126)
ctx->lengthToRead = 6; /* longueur sur 2 octets a suivre (+ masking key) */
else
ctx->lengthToRead = 12; /* forcement 127 ici => longueur sur 8 octets a suivre (+ masking key) */
/* */
ctx->state = WSSTATE_READINGFRAMEHEADEREXT;
}
}
/* */
if(ctx->state == WSSTATE_READINGFRAMEHEADEREXT)
{
if(data->mLg == 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
/* lecture longueur si sur 2/8 octets + masking key */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->frameHeader, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues, decodage de la frame */
dynConcatSz(e, &ctx->frameHeader, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
/* */
int posMaskey = 2;
if(ctx->len < 126)
ctx->lengthToRead = ctx->len;
else if(ctx->len == 126)
{
ctx->lengthToRead = (ent64s)ctx->frameHeader.ptr[2] + ((ent64s)ctx->frameHeader.ptr[3] << 8);
posMaskey = 4;
}
else
{
ctx->lengthToRead = (ent64s)ctx->frameHeader.ptr[2] + ((ent64s)ctx->frameHeader.ptr[3] << 8) ;
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[4] << 16) + ((ent64s)ctx->frameHeader.ptr[5] << 24);
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[6] << 32) + ((ent64s)ctx->frameHeader.ptr[7] << 40);
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[8] << 48) + ((ent64s)ctx->frameHeader.ptr[9] << 56);
posMaskey = 10;
}
memcpy(ctx->maskey, ctx->frameHeader.ptr + posMaskey, 4);
/* */
ctx->state = WSSTATE_READINGFRAMECONTENT;
}
}
/* */
if(ctx->state == WSSTATE_READINGFRAMECONTENT)
{
if(data->mLg == 0 && ctx->lengthToRead != 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, ctx->controlInFragment ? &ctx->contentControl : &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues */
if(ctx->lengthToRead != 0)
{
dynConcatSz(e, ctx->controlInFragment ? &ctx->contentControl : &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
}
/* appliquer le maskey a chaque octet lu */
if( ! ctx->controlInFragment)
for(long cpt = 0; cpt < ctx->content.mLg; cpt++)
ctx->content.ptr[cpt] ^= ctx->maskey[cpt % 4];
else
for(long cpt = 0; cpt < ctx->contentControl.mLg; cpt++)
ctx->contentControl.ptr[cpt] ^= ctx->maskey[cpt % 4];
/* ping : envoyer pong 0xA1, 0x00, pong ras, close couper la comm' + reset proto websocket */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->lengthToRead = 0;
ctx->controlInFragment = FALSE;
if(ctx->opcode == WS_FRAME_OPCODE_CLOSE)
return WS_REQUEST_CLOSE;
else if(ctx->opcode == WS_FRAME_OPCODE_PING)
return WS_REQUEST_PING;
else if(ctx->opcode == WS_FRAME_OPCODE_PONG)
return WS_REQUEST_PONG;
else
return (ctx->fragment ? WS_REQUEST_FRAGMENT : WS_REQUEST_COMPLETE);
}
}
/* */
ctx->state = WSSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
return WS_REQUEST_ERROR;
}
WAPIDECL long MakeExpectContent(env * e, modCtxWs * ctx, Dynamic * reponse)
{
dynLet(e, reponse, ctx->line.mPtr, ctx->line.mLg); /* handshake http before framing control */
return OK;
}
WAPIDECL long MakeFrame(env * e, modCtxWs * ctx, int frameType, Dynamic * data, Dynamic * response)
{
if(frameType != WS_FRAME_OPCODE_CLOSE && frameType != WS_FRAME_OPCODE_PING && frameType != WS_FRAME_OPCODE_PONG &&
frameType != WS_FRAME_OPCODE_TEXT && frameType != WS_FRAME_OPCODE_BINARY)
return WS_OPCODE_KO;
ent64s lg = 0;
if(data)
if((lg = data->mLg) > 65536ll * 65536ll)
return WS_LENGTH_TOO_HIGH; /* what if length too high : fragment ? refuse ? */
/* */
dynSetLen(e, response, 0);
response->ptr[0] = (frameType << 4) + WS_FRAME_FRAGMENT_OFF;
int posMaskey = 2;
if(lg < 126)
response->ptr[1] = (((octet)lg) << 1) + WS_FRAME_MASK_OFF; // only server mode, and so no masking
else if(lg < 65536)
{
response->ptr[1] = (((octet)126) << 1) + WS_FRAME_MASK_OFF;
response->ptr[2] = (octet)(lg & 255); /* 2 bytes, little endian */
response->ptr[3] = (octet)(lg >> 8);
posMaskey = 4;
}
else
{
response->ptr[1] = (((octet)127) << 1) + WS_FRAME_MASK_OFF;
response->ptr[2] = (octet)(lg & 255); /* 8 bytes, little endian */
response->ptr[3] = (octet)((lg >> 8) & 255);
response->ptr[4] = (octet)((lg >> 16) & 255);
response->ptr[5] = (octet)((lg >> 24) & 255);
response->ptr[6] = (octet)((lg >> 32) & 255);
response->ptr[7] = (octet)((lg >> 40) & 255);
response->ptr[8] = (octet)((lg >> 48) & 255);
response->ptr[9] = (octet)(lg >> 56);
posMaskey = 10;
}
/* for instance, no mask key */
if( ! dynCtrl(e, response, posMaskey + lg, TRUE))
{
dynSetLen(e, response, 0);
return WS_MEMORY;
}
if(lg > 0)
memcopie(response->ptr + posMaskey, data->ptr, lg);
dynSetLen(e, response, posMaskey + lg);
/* */
return OK;
}
+6 -3
View File
@@ -1,4 +1,4 @@
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
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,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102
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
@@ -51,6 +51,8 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
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,73;1,1,71;1,1,72;1,1,74
1,1,65;1,1,78;1,1,70
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
@@ -58,6 +60,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
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,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
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
@@ -80,7 +83,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,5B
1,1,5D
1,1,21
1,1,3F
1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66
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
@@ -97,4 +100,4 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,2C
1,1,2E
1,1,26
1,1,00-FF
1,1,00-FF