Compare commits
89
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f886792a2b | ||
|
|
de896eb2ba | ||
|
|
0d32522c75 | ||
|
|
d65cf3d2fa | ||
|
|
e6dbc8c814 | ||
|
|
dc3e7c882d | ||
|
|
550c4ff5d6 | ||
|
|
b100fd2959 | ||
|
|
598d7321c4 | ||
|
|
3d0629b628 | ||
|
|
bce2033fc1 | ||
|
|
6c58dc64cc | ||
|
|
6894685bb9 | ||
|
|
7f5fb882da | ||
|
|
97065a4e47 | ||
|
|
4ed586d2dc | ||
|
|
a20c4733ad | ||
|
|
ecb07de56e | ||
|
|
9b04cf31ac | ||
|
|
6f88a95edd | ||
|
|
48719bc369 | ||
|
|
4e7ba72eda | ||
|
|
726df4dcb9 | ||
|
|
b6bea78591 | ||
|
|
0445f10ebe | ||
|
|
ad317a2070 | ||
|
|
e0eaf6f9e8 | ||
|
|
b70cee802b | ||
|
|
84bdea04ea | ||
|
|
747c9819f1 | ||
|
|
44b447e9af | ||
|
|
760020f30e | ||
|
|
3f4f548e55 | ||
|
|
4c80dff382 | ||
|
|
632df00f8d | ||
|
|
667531bee8 | ||
|
|
0ec33cbe5a | ||
|
|
efbd77e7fb | ||
|
|
89dcd0b594 | ||
|
|
3b68b7d408 | ||
|
|
e39c18d606 | ||
|
|
fc29d78e57 | ||
|
|
cb12b9d54f | ||
|
|
bcd62e6913 | ||
|
|
89a3c4d5c2 | ||
|
|
103ad22814 | ||
|
|
c69d94e6c8 | ||
|
|
f994cc8188 | ||
|
|
e87d3f9237 | ||
|
|
0f55fc23f3 | ||
|
|
fa533a0a2d | ||
|
|
5ddbd73146 | ||
|
|
80847f4993 | ||
|
|
1fe89c0b6a | ||
|
|
ddbbb29038 | ||
|
|
eca0605104 | ||
|
|
72f749172f | ||
|
|
5c58e7ba97 | ||
|
|
c036ec478c | ||
|
|
a23c183f7d | ||
|
|
dc02ac4243 | ||
|
|
280b10ca99 | ||
|
|
db24144e31 | ||
|
|
efd1b9a91d | ||
|
|
33d9ca87c0 | ||
|
|
4983647ad1 | ||
|
|
dea729767e | ||
|
|
aa61937a20 | ||
|
|
01113671ec | ||
|
|
68d3311b01 | ||
|
|
55ad7180e1 | ||
|
|
a2505eabf7 | ||
|
|
2ad1bada78 | ||
|
|
8460963bc3 | ||
|
|
4cbc937c45 | ||
|
|
f60884882c | ||
|
|
2a07637008 | ||
|
|
6f207a7ed4 | ||
|
|
2ffcab88b3 | ||
|
|
a3cc520837 | ||
|
|
22de8f85c5 | ||
|
|
7019ea7f8b | ||
|
|
799c7c7548 | ||
|
|
961994d6c7 | ||
|
|
f8f63d87d4 | ||
|
|
3384b0df85 | ||
|
|
fcb62ff71c | ||
|
|
0871ed56fc | ||
|
|
a6f8d2aefa |
No files matched your search
@@ -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://www.lanisys.fr/wiki/doku.php?id=w
|
||||
# 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).
|
||||
@@ -0,0 +1,34 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
// for windows compilation and generating/using import library
|
||||
#ifdef WAPIEXPORT
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#endif
|
||||
#ifdef WAPIIMPORT
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllimport)
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
#define ARG_DEBUG "d" /* avec lw */
|
||||
#define ARG_TRACE "t" /* avec lw */
|
||||
#define ARG_BACKGROUND "b" /* avec lw (process deja lance en background) */
|
||||
#define ARG_DISASM "u" /* avec lwa */
|
||||
#define ARG_COMPRESS "c" /* avec lwa (compression du wp genere, assemblage) */
|
||||
#define ARG_SOURCE "s" /* avec lwc */
|
||||
|
||||
void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
|
||||
{
|
||||
int nbOpt = 0, cpt = 0, clc = 0;
|
||||
dynSetLen(e, arg, 0);
|
||||
dynStoreSz(e, arg, 6, ++clc, argv[0], DYN_LGNONE, cFM, cVM);
|
||||
for(int a = 1; a < argc; a++)
|
||||
{
|
||||
dynStoreSz(e, arg, 6, ++clc, argv[a], DYN_LGNONE, cFM, cVM);
|
||||
//
|
||||
if(strcmp(argv[a], "-" ARG_DEBUG) == 0)
|
||||
dynStoreSz(e, arg, 1, ++nbOpt, ARG_DEBUG, 1, cFM, cVM);
|
||||
else if(strcmp(argv[a], "-" ARG_TRACE) == 0)
|
||||
dynStoreSz(e, arg, 1, ++nbOpt, ARG_TRACE, 1, cFM, cVM);
|
||||
else if(strcmp(argv[a], "-" ARG_BACKGROUND) == 0)
|
||||
dynStoreSz(e, arg, 1, ++nbOpt, ARG_BACKGROUND, 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)
|
||||
dynStoreSz(e, arg, 5, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.wp .wa)
|
||||
else if(strncmp(argv[a], "-WSRC:", 6) == 0 && strlen(argv[a]) > 6)
|
||||
dynStoreSz(e, arg, 4, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.w)
|
||||
else if(strncmp(argv[a], "-", 1) == 0)
|
||||
; // argument inconnu, ignorer
|
||||
else
|
||||
{
|
||||
// premier argument ne commencant pas par "-" : nom du prog wp
|
||||
dynDel(e, arg, 6, clc, cFM, cVM, 1);
|
||||
for( ; a < argc; a++)
|
||||
dynStoreSz(e, arg, 2, ++cpt, argv[a], DYN_LGNONE, cFM, cVM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(dynExtractPos(e, arg, 3, DYN_NONE, cFM, DYN_NONE) <= 0)
|
||||
{
|
||||
dynStoreSz(e, arg, 3, DYN_NONE, getenv("WBIN"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
|
||||
if(dynExtractPos(e, arg, 3, DYN_NONE, cFM, DYN_NONE) <= 0)
|
||||
dynStoreSz(e, arg, 3, DYN_NONE, getenv("LD_LIBRARY_PATH"), DYN_LGNONE, cFM, DYN_NONE); // dernier recours...
|
||||
}
|
||||
//
|
||||
if(dynExtractPos(e, arg, 5, DYN_NONE, cFM, DYN_NONE) <= 0)
|
||||
dynStoreSz(e, arg, 5, DYN_NONE, getenv("WLIB"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
|
||||
//
|
||||
if(dynExtractPos(e, arg, 4, DYN_NONE, cFM, DYN_NONE) <= 0)
|
||||
dynStoreSz(e, arg, 4, DYN_NONE, getenv("WSRC"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
|
||||
/*
|
||||
arg<1> = options 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
|
||||
arg<6> = les argv ligne de commande AVANT le prog wp
|
||||
*/
|
||||
}
|
||||
+273
-286
File diff suppressed because it is too large.
Load diff
@@ -29,7 +29,46 @@
|
||||
#include "buffer.h"
|
||||
#include "dynamic.h"
|
||||
|
||||
void buffer_read(env * e, var * varbuf, var * v)
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
/*
|
||||
Dans le contexte des IPC, memoire partagee, contenant un buffer (donc partagé), le champ "ptr" pointe forcement a la suite de l'entete,
|
||||
car un malloc ne fonctionne pas en inter process.
|
||||
Contrairement à la création avec "var_init", destiné a ne pas etre partage, ptr est créé par un malloc
|
||||
La macro BUFPTR permet de gerer ces 2 cas : si le buffer est en memoire partagee, le champ ptr = NULL et il suffit alors d'aller juste apres l'entete
|
||||
pour trouver les donnees. Si le buffer est cree avec var_init, il faut utiliser la valeur de ptr directement.
|
||||
*/
|
||||
/*
|
||||
lgmax = taille buffer
|
||||
max lg message = lgmax - 4 => un message = lg (2 octets) + msg
|
||||
|
||||
cas 0 read = write : buffer vide : lg msg max = lgmax - 4 (et maxi 65535)
|
||||
|
||||
cas 1 : read <= write (inclus cas 0)
|
||||
+-------------^*********************^------------------+ lgmax
|
||||
read write
|
||||
occ = write - read ; free = lgmax - (write - read) - 4
|
||||
|
||||
cas 2 : read > write
|
||||
+********^---------------------------------------^*****+ lgmax
|
||||
write read
|
||||
occ = write + (lgmax - read) ; free = read - write - 4
|
||||
*/
|
||||
|
||||
//#define BUFPTR(x) (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr)
|
||||
pointeur BUFPTR(var * x)
|
||||
{
|
||||
return (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr);
|
||||
}
|
||||
|
||||
WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
|
||||
{
|
||||
ent16 lg, lgfin; /* taille max d'un element dans un buffer : 64 Ko */
|
||||
ent64 p;
|
||||
@@ -37,9 +76,16 @@ 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);
|
||||
@@ -56,9 +102,9 @@ void buffer_read(env * e, var * varbuf, var * v)
|
||||
return; /* buffer vide : var dynamic vide aussi */
|
||||
/* */
|
||||
p = varbuf->read;
|
||||
lg = *(octet *)(varbuf->ptr + p++) * 256;
|
||||
lg = *(octet *)(BUFPTR(varbuf) + p++) * 256;
|
||||
if(p >= varbuf->lgmax) p = 0;
|
||||
lg += *(octet *)(varbuf->ptr + p++);
|
||||
lg += *(octet *)(BUFPTR(varbuf) + p++);
|
||||
if(p >= varbuf->lgmax) p = 0;
|
||||
if(lg > 0)
|
||||
{
|
||||
@@ -68,8 +114,7 @@ void buffer_read(env * e, var * varbuf, var * v)
|
||||
if(lg <= (lgfin = varbuf->lgmax - p))
|
||||
{
|
||||
/* copier un seul bloc */
|
||||
memcopie(v->ptr, varbuf->ptr + p, lg);
|
||||
//memcpy(v->ptr, varbuf->ptr + p, lg);
|
||||
memcopie(v->ptr, BUFPTR(varbuf) + p, lg);
|
||||
v->lg = lg;
|
||||
*(v->ptr + lg) = 0; /* \0 de fin de chaine */
|
||||
if(p + lg >= varbuf->lgmax)
|
||||
@@ -80,10 +125,8 @@ void buffer_read(env * e, var * varbuf, var * v)
|
||||
else
|
||||
{
|
||||
/* 2 blocs */
|
||||
memcopie(v->ptr, varbuf->ptr + p, lgfin);
|
||||
//memcpy(v->ptr, varbuf->ptr + p, lgfin);
|
||||
memcopie(v->ptr + lgfin, varbuf->ptr, lg - lgfin);
|
||||
//memcpy(v->ptr + lgfin, varbuf->ptr, lg - lgfin);
|
||||
memcopie(v->ptr, BUFPTR(varbuf) + p, lgfin);
|
||||
memcopie(v->ptr + lgfin, BUFPTR(varbuf), lg - lgfin);
|
||||
varbuf->read = lg - lgfin;
|
||||
}
|
||||
}
|
||||
@@ -91,17 +134,23 @@ void buffer_read(env * e, var * varbuf, var * v)
|
||||
varbuf->read = p;
|
||||
}
|
||||
|
||||
void buffer_write(env * e, var * varbuf, var * v)
|
||||
WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
|
||||
{
|
||||
ent64 p, lgfin;
|
||||
if(varbuf == NULL || v == NULL)
|
||||
return;
|
||||
if(v->type == VAR_PARAM)
|
||||
v = (var *)v->ptr; /* travailler avec la var pointee ! */
|
||||
{
|
||||
if((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 > (v->lgmax / 16)) // pour pouvoir ecrire au moins 16 items dans le buffer
|
||||
if(v->lg > (varbuf->lgmax / 2)) // pour pouvoir ecrire au moins 2 items dans le buffer
|
||||
{
|
||||
e->exception = EX_BUFOVF; /* trop grand a ecrire */
|
||||
return;
|
||||
@@ -117,12 +166,11 @@ void buffer_write(env * e, var * varbuf, var * v)
|
||||
}
|
||||
/* */
|
||||
p = varbuf->write;
|
||||
*(varbuf->ptr + p) = (v->lg & 65535) >> 8;
|
||||
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
|
||||
p++;
|
||||
*(varbuf->ptr + p) = v->lg & 255;
|
||||
*(BUFPTR(varbuf) + p) = v->lg & 255;
|
||||
p++;
|
||||
memcopie(varbuf->ptr + p, v->ptr, v->lg);
|
||||
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
|
||||
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
|
||||
varbuf->write = p + v->lg;
|
||||
}
|
||||
else
|
||||
@@ -133,12 +181,11 @@ void buffer_write(env * e, var * varbuf, var * v)
|
||||
e->exception = EX_BUFOVF; /* pas assez de place */
|
||||
return;
|
||||
}
|
||||
/* */
|
||||
p = varbuf->write;
|
||||
*(varbuf->ptr + p) = (v->lg & 65535) >> 8;
|
||||
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
|
||||
p++;
|
||||
if(p >= varbuf->lgmax) p = 0;
|
||||
*(varbuf->ptr + p) = v->lg & 255;
|
||||
*(BUFPTR(varbuf) + p) = v->lg & 255;
|
||||
p++;
|
||||
if(p >= varbuf->lgmax) p = 0;
|
||||
if(v->lg == 0)
|
||||
@@ -149,8 +196,7 @@ void buffer_write(env * e, var * varbuf, var * v)
|
||||
if(v->lg <= (lgfin = varbuf->lgmax - p))
|
||||
{
|
||||
/* copier en une fois */
|
||||
memcopie(varbuf->ptr + p, v->ptr, v->lg);
|
||||
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
|
||||
memcopie(BUFPTR(varbuf) + 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
|
||||
@@ -159,16 +205,14 @@ void buffer_write(env * e, var * varbuf, var * v)
|
||||
else
|
||||
{
|
||||
/* en 2 fois */
|
||||
memcopie(varbuf->ptr + p, v->ptr, lgfin);
|
||||
//memcpy(varbuf->ptr + p, v->ptr, lgfin);
|
||||
memcopie(varbuf->ptr, v->ptr + lgfin, v->lg - lgfin);
|
||||
//memcpy(varbuf->ptr, v->ptr + lgfin, v->lg - lgfin);
|
||||
memcopie(BUFPTR(varbuf) + p, v->ptr, lgfin);
|
||||
memcopie(BUFPTR(varbuf), v->ptr + lgfin, v->lg - lgfin);
|
||||
varbuf->write = v->lg - lgfin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void buffer_clear(env * e, var * varbuf)
|
||||
WAPIDECL void buffer_clear(env * e, var * varbuf)
|
||||
{
|
||||
if(varbuf == NULL)
|
||||
return;
|
||||
@@ -176,10 +220,10 @@ void buffer_clear(env * e, var * varbuf)
|
||||
return;
|
||||
varbuf->read = 0;
|
||||
varbuf->write = 0;
|
||||
memset(varbuf->ptr, 0, varbuf->lgmax);
|
||||
memset(BUFPTR(varbuf), 0, varbuf->lgmax);
|
||||
}
|
||||
|
||||
void buffer_printdebug(env * e, var * varbuf, ent32 lg)
|
||||
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg)
|
||||
{
|
||||
if(varbuf == NULL)
|
||||
return;
|
||||
@@ -189,5 +233,5 @@ void buffer_printdebug(env * e, var * varbuf, ent32 lg)
|
||||
if(lg == 0)
|
||||
lg = varbuf->lgmax;
|
||||
/* affichage brut en hexa */
|
||||
hex2((char *)varbuf->ptr, lg, 32);
|
||||
hex2((char *)BUFPTR(varbuf), lg, 32);
|
||||
}
|
||||
@@ -23,11 +23,13 @@
|
||||
#ifndef BUFFER_H
|
||||
#define BUFFER_H
|
||||
|
||||
void buffer_read(env * e, var * varbuf, var * v);
|
||||
void buffer_write(env * e, var * varbuf, var * v);
|
||||
void buffer_clear(env * e, var * varbuf);
|
||||
#include "apidecl.h"
|
||||
|
||||
void buffer_printdebug(env * e, var * varbuf, ent32 lg);
|
||||
WAPIDECL void buffer_read(env * e, var * varbuf, var * v);
|
||||
WAPIDECL void buffer_write(env * e, var * varbuf, var * v);
|
||||
WAPIDECL void buffer_clear(env * e, var * varbuf);
|
||||
|
||||
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg);
|
||||
|
||||
/* ********************************************** */
|
||||
#endif
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -1,42 +1,71 @@
|
||||
BUILD=`date +%Y%m%d%H%M%S`
|
||||
echo BUILD $BUILD
|
||||
|
||||
echo 0. Compilation pour shared lib
|
||||
gcc -c w_src/dynamic.c -s -Wall -DUNIX -m64 -fPIC -o exec/dynamic.o -Wno-unused-value
|
||||
gcc -c w_src/var.c -s -Wall -DUNIX -m64 -fPIC -o exec/var.o
|
||||
gcc -c w_src/hashtable.c -s -Wall -DUNIX -m64 -fPIC -o exec/hashtable.o
|
||||
gcc -c w_src/buffer.c -s -Wall -DUNIX -m64 -fPIC -o exec/buffer.o
|
||||
gcc -c w_src/global.c -s -Wall -DUNIX -m64 -fPIC -o exec/global.o
|
||||
gcc -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 -o exec/libw.so
|
||||
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.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 modeleMod.c
|
||||
gcc -shared -s -o exec/modele.o w_src/modeleMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
echo 1. Compilation de templateMod.c
|
||||
gcc -shared -s -o exec/template.o w_src/templateMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
|
||||
echo 2. Compilation de fileMod.c
|
||||
gcc -shared -s -o exec/file.o w_src/fileMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
|
||||
echo 3. Compilation de sockMod.c
|
||||
gcc -shared -s -o exec/sock.o w_src/sockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/sock_lib.so w_src/sock_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/sock.o w_src/sockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:sock_lib.so
|
||||
|
||||
echo 4. Compilation de dbMod.c et dbpgsql.c
|
||||
gcc -shared -s -o exec/db.o w_src/dbMod.c -m64 -DUNIX -Wall -ldl -fPIC -L./exec -l:libw.so
|
||||
echo 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 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.o w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/lzw.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:lzw_lib.o
|
||||
gcc -shared -s -o exec/lzw_lib.so w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/lzw.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:lzw_lib.so
|
||||
|
||||
echo 5. Compilation de pdfMod.c
|
||||
gcc -shared -s -o exec/pdf_lib.o w_src/pdf_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
#gcc -shared -s -o exec/pdf.o w_src/pdfMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:pdf_lib.o
|
||||
gcc -shared -s -o exec/pdf_lib.so w_src/pdf_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/pdf.o w_src/pdfMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:pdf_lib.so -l:lzw_lib.so
|
||||
|
||||
echo 6. Compilation de jsonMod.c
|
||||
gcc -shared -s -o exec/json_lib.o w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.o
|
||||
gcc -shared -s -o exec/json_lib.so w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.so
|
||||
|
||||
echo 6. Compilation de shmMod.c
|
||||
gcc -shared -s -o exec/shm_lib.so w_src/shm_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
gcc -shared -s -o exec/shm.o w_src/shmMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:shm_lib.so
|
||||
|
||||
echo 7. Compilation de timeMod.c
|
||||
gcc -shared -s -o exec/time.o w_src/timeMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
|
||||
|
||||
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
|
||||
@@ -44,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 -Wall -Wno-stringop-truncation -L./exec -l:libw.so
|
||||
gcc w_src/langage.c -s -o exec/lw -ldl -m64 -DUNIX -DBUILD=$BUILD -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:shm_lib.so -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
|
||||
@@ -59,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_pdf => gcc test_pdf.c -s -o pdf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:pdf_lib.o -l:lzw_lib.o"
|
||||
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"
|
||||
+83
-59
@@ -5,81 +5,105 @@ call vcvars64.bat
|
||||
|
||||
cd "C:\Users\Poupougne42\source\repos\win_w_src"
|
||||
|
||||
echo 0. Compilation pour static lib
|
||||
cl /c /Foexec\dynamic.obj w_src\dynamic.c
|
||||
cl /c /Foexec\var.obj w_src\var.c
|
||||
cl /c /Foexec\hashtable.obj w_src\hashtable.c
|
||||
cl /c /Foexec\global.obj w_src\global.c
|
||||
cl /c /Foexec\rep.obj w_src\rep.c
|
||||
echo ------------------------------------------------------------------------------------------
|
||||
echo 0. Compilation pour dynamic lib DLL
|
||||
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\libw.dll w_src\dynamic.c w_src\var.c w_src\hashtable.c w_src\buffer.c w_src\global.c w_src\rep.c w_src\lex.c w_src\convert.c /DEBUG:NONE
|
||||
|
||||
echo 1a. Compilation de templateMod.c
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\template.dll w_src\templateMod.c exec\libw.lib /DEBUG:NONE
|
||||
|
||||
lib /OUT:exec\libw.lib exec\dynamic.obj exec\var.obj exec\hashtable.obj exec\global.obj exec\rep.obj
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1a. Compilation de modeleMod.c
|
||||
cl w_src\modeleMod.c exec\libw.lib /Foexec\modeleMod.obj /DWINLIB /link /DLL /OUT:exec\modele.dll
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1b. Compilation de fileMod.c
|
||||
cl w_src\fileMod.c exec\libw.lib /Foexec\fileMod.obj /DWINLIB /link /DLL /OUT:exec\file.dll
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\file.dll w_src\fileMod.c exec\libw.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1c. Compilation de jsonMod.c
|
||||
cl /c /Foexec\json_lib.obj w_src\json_lib.c
|
||||
lib /OUT:exec\json_lib.lib exec\json_lib.obj
|
||||
cl w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /Foexec\jsonMod.obj /DWINLIB /link /DLL /OUT:exec\json.dll
|
||||
echo 1c. Compilation de timeMod.c
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\time.dll w_src\timeMod.c exec\libw.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1d. Compilation de timeMod.c
|
||||
cl w_src\timeMod.c exec\libw.lib /Foexec\timeMod.obj /DWINLIB /link /DLL /OUT:exec\time.dll
|
||||
echo 1d. Compilation de hashMod.c
|
||||
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 ------------------------------------------------------------------------
|
||||
echo 1e. Compilation de hashMod.c
|
||||
cl w_src\hashMod.c exec\libw.lib /Foexec\hashMod.obj /DWINLIB /link /DLL /OUT:exec\hash.dll
|
||||
echo 1e. Compilation de systemMod.c (ws2_32.lib pour socket)
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\system.dll w_src\systemMod.c exec\libw.lib ws2_32.lib advapi32.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1f. Compilation de systemMod.c
|
||||
cl w_src\systemMod.c exec\libw.lib ws2_32.lib /Foexec\systemMod.obj /DWINLIB /link /DLL /OUT:exec\system.dll
|
||||
echo 1f. Compilation de randomMod.c
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\random.dll w_src\randomMod.c exec\libw.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1g. Compilation de randomMod.c
|
||||
cl w_src\randomMod.c exec\libw.lib /Foexec\randomMod.obj /DWINLIB /link /DLL /OUT:exec\random.dll
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1h. Compilation de lzwMod.c
|
||||
cl /c /Foexec\lzw_lib.obj w_src\lzw_lib.c
|
||||
lib /OUT:exec\lzw_lib.lib exec\lzw_lib.obj
|
||||
cl w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib /Foexec\lzwMod.obj /DWINLIB /link /DLL /OUT:exec\lzw.dll
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 1h. Compilation de pdfMod.c
|
||||
cl /c /Foexec\pdf_lib.obj w_src\pdf_lib.c
|
||||
lib /OUT:exec\pdf_lib.lib exec\pdf_lib.obj
|
||||
rem cl w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib /Foexec\pdfMod.obj /DWINLIB /link /DLL /OUT:exec\pdf.dll
|
||||
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 2. Compilation langage lw (ws2_32.lib pour socket)
|
||||
cl w_src\langage.c exec\libw.lib ws2_32.lib /Foexec\langage.obj /DWINLIB /link /OUT:exec\lw.exe
|
||||
echo ------------------------------------------------------------------------------------------
|
||||
echo 2a. Compilation de jsonMod.c
|
||||
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\json_lib.dll w_src\json_lib.c exec\libw.lib /DEBUG:NONE
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 3. Compilation assembleur lwa
|
||||
cl w_src\assembler.c exec\libw.lib /Foexec\assembler.obj /DWINLIB /link /OUT:exec\lwa.exe
|
||||
echo 2b. Compilation de shmMod.c
|
||||
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\shm_lib.dll w_src\shm_lib.c exec\libw.lib advapi32.lib /DEBUG:NONE
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\shm.dll w_src\shmMod.c exec\libw.lib exec\shm_lib.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 4. Compilation du compilateur W (generateur d'assembleur)
|
||||
cl w_src\genw.c exec\libw.lib /Foexec\genw.obj /DWINLIB /link /OUT:exec\lwc.exe
|
||||
echo 2c. Compilation de lzwMod.c
|
||||
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\lzw_lib.dll w_src\lzw_lib.c exec\libw.lib /DEBUG:NONE
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lzw.dll w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 5. Compilation formatteur de code w
|
||||
cl w_src\format.c exec\libw.lib /Foexec\format.obj /DWINLIB /link /OUT:exec\lwf.exe
|
||||
echo 2d. Compilation de pdfMod.c
|
||||
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\pdf_lib.dll w_src\pdf_lib.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\pdf.dll w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib /DEBUG:NONE
|
||||
|
||||
echo ------------------------------------------------------------------------
|
||||
echo 6. Generation du generateur de fichier lex
|
||||
cl w_src\genlex.c exec\libw.lib /Foexec\genlex.obj /DWINLIB /link /OUT:exec\wlex.exe
|
||||
echo 2e. Compilation de sockMod.c
|
||||
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sock_lib.dll w_src\sock_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE
|
||||
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\sock.dll w_src\sockMod.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE
|
||||
|
||||
rem purge des .obj
|
||||
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 /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 /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 /Gy /MD /Feexec\lwc.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
|
||||
|
||||
echo 3d. Generation lwf.exe
|
||||
cl w_src\format.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwf.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
|
||||
|
||||
echo 3d. Generation wlex.exe
|
||||
cl w_src\genlex.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\wlex.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
|
||||
|
||||
rem echo 3e. Generation test.exe
|
||||
rem cl w_src\test.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\test.exe exec\libw.lib exec\encod_lib.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
|
||||
|
||||
echo ------------------------------------------------------------------------------------------
|
||||
echo 4. Purge
|
||||
del .\*.obj
|
||||
del exec\*.obj
|
||||
del exec\*.lib
|
||||
del exec\*.exp
|
||||
dir exec
|
||||
exit
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "langage.h"
|
||||
#include "convert.h"
|
||||
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
/* ****** PRIVATE ************************ */
|
||||
|
||||
static char hexa[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
|
||||
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 128 cars a la fin de cette ligne */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
|
||||
|
||||
static char carhex[16] = {"0123456789abcdef"};
|
||||
|
||||
static char base64[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* '+' = 62 ; '/' = 63 ; '-' (62) se trouve au milieu entre les deux */
|
||||
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,99,-1,-1, /* '=' mis a 99 */
|
||||
-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
|
||||
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* dernier -1 ici = '_' (63) */
|
||||
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
|
||||
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 128 cars a la fin de cette ligne */
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; // "=" mis a 99
|
||||
|
||||
static char carBase64[65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}; /* et caractere "=" en complement */
|
||||
// TODO static char carBase64url[65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="}; /* et caractere "=" en complement */
|
||||
|
||||
/* TODO compatible UTF8 !! */
|
||||
|
||||
/* ****** PUBLIC ************************ */
|
||||
WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat)
|
||||
{
|
||||
if(this->mLg == 0)
|
||||
{
|
||||
dynSetLen(e, resultat, 0);
|
||||
return DYN_OK;
|
||||
}
|
||||
if(dynCtrl(e, resultat, this->mLg * 2, DYN_FALSE)) /* chaine hexa : taille double de celle origine */
|
||||
return DYN_ERR;
|
||||
long from = this->mLg - 1;
|
||||
long to = from * 2 + 1;
|
||||
/* cette methode fonctionne aussi si this et resultat pointent sur la meme variable... mettre TRUE dans dynCtrl alors ! */
|
||||
for( ;from >= 0; )
|
||||
{
|
||||
resultat->ptr[to--] = carhex[this->ptr[from] % 16];
|
||||
resultat->ptr[to--] = carhex[this->ptr[from--] / 16];
|
||||
}
|
||||
dynSetLen(e, resultat, this->mLg * 2);
|
||||
return DYN_OK;
|
||||
}
|
||||
|
||||
WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat)
|
||||
{
|
||||
/* conversion en base64 /base64url */
|
||||
/* 3 cars en clair en donne 4 en base 64 ; si le dernier bloc contient 2 cars, la sortie est de 3 cars */
|
||||
/* + car "=" ; si le dernier bloc contient 1 car, la sortie est de 2 cars + deux cars "=" */
|
||||
/* quand le dernier bloc contient 1 ou 2 cars, les bits manquants pour avoir des octets complets sont mis a 0 */
|
||||
/* +-------------+-----------+-------------+ */
|
||||
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
|
||||
/* +---------+---------+---------+---------+ */
|
||||
/* */
|
||||
if(this->mLg == 0)
|
||||
{
|
||||
dynSetLen(e, resultat, 0);
|
||||
return DYN_OK;
|
||||
}
|
||||
long lg64 = this->mLg / 3;
|
||||
if(this->mLg % 3 != 0)
|
||||
lg64++;
|
||||
lg64 *= 4; // longueur finale du base64
|
||||
if(dynCtrl(e, resultat, lg64, DYN_FALSE))
|
||||
return DYN_ERR;
|
||||
/* */
|
||||
long from, to;
|
||||
for(from = 0, to = 0; from < this->mLg; from += 3)
|
||||
{
|
||||
if(from + 1 >= this->mLg)
|
||||
{
|
||||
/* bloc de 1 octet => 2 cars en sortie + 2 cars de complement */
|
||||
resultat->mPtr[to++] = carBase64[this->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->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->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];
|
||||
}
|
||||
}
|
||||
/* */
|
||||
dynSetLen(e, resultat, lg64);
|
||||
return DYN_OK;
|
||||
}
|
||||
|
||||
WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat)
|
||||
{
|
||||
if(this->mLg == 0)
|
||||
{
|
||||
dynSetLen(e, resultat, 0);
|
||||
return DYN_OK;
|
||||
}
|
||||
if(this->mLg % 2 != 0)
|
||||
return DYN_ERR; /* erreur format hexa incorrect */
|
||||
if(dynCtrl(e, resultat, this->mLg / 2, DYN_FALSE))
|
||||
return DYN_ERR;
|
||||
/* */
|
||||
char c1, c2;
|
||||
long from, to;
|
||||
for(from = 0, to = 0; from < this->mLg; from += 2)
|
||||
{
|
||||
if((c1 = hexa[this->ptr[from]]) == -1 || (c2 = hexa[this->ptr[from + 1]]) == -1)
|
||||
{
|
||||
dynSetLen(e, resultat, 0);
|
||||
return DYN_ERR; /* erreur format hexa incorrect */
|
||||
}
|
||||
resultat->ptr[to++] = (c1 << 4) | c2;
|
||||
}
|
||||
dynSetLen(e, resultat, this->mLg / 2);
|
||||
return DYN_OK;
|
||||
}
|
||||
|
||||
WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat)
|
||||
{
|
||||
|
||||
/* conversion en clair de la chaine en base64 */
|
||||
/* +-------------+-----------+-------------+ */
|
||||
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
|
||||
/* +---------+---------+---------+---------+ */
|
||||
if(this->mLg == 0)
|
||||
{
|
||||
dynSetLen(e, resultat, 0);
|
||||
return DYN_OK;
|
||||
}
|
||||
if(this->mLg % 4 != 0)
|
||||
return DYN_ERR; /* erreur format base64 incorrect */
|
||||
long lgClair = (this->mLg / 4) * 3;
|
||||
if(dynCtrl(e, resultat, lgClair, DYN_FALSE))
|
||||
return DYN_ERR;
|
||||
/* */
|
||||
long from, to;
|
||||
for(from = 0, to = 0; from < this->mLg; from += 4, to += 3)
|
||||
{
|
||||
char c1 = base64[this->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->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->ptr[to + 1] = (c2 & 15) << 4;
|
||||
resultat->ptr[to + 1] |= c3 >> 2;
|
||||
if(c4 != 99)
|
||||
{
|
||||
resultat->ptr[to + 2] = (c3 & 3) << 6;
|
||||
resultat->ptr[to + 2] |= c4;
|
||||
}
|
||||
else
|
||||
lgClair--;
|
||||
}
|
||||
else
|
||||
lgClair--;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#ifndef CONVERT_H
|
||||
#define CONVERT_H
|
||||
|
||||
#include "dynamic.h"
|
||||
|
||||
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
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -77,16 +77,24 @@ 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 */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
if(modFnIs(e, "init", 4))
|
||||
{
|
||||
// alloc ptr sur zone memoire pour memoriser l'etat du module
|
||||
*etat = memalloc(e, sizeof(modEtat));
|
||||
@@ -97,43 +105,49 @@ 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(strncmp(e->fn, "end", 3) == 0)
|
||||
else if(modFnIs(e, "end", 3))
|
||||
{
|
||||
//*** code specifique ici
|
||||
//
|
||||
// liberation specifique au module avant arret process
|
||||
if(p_etat != NULL)
|
||||
memfree(e, p_etat);
|
||||
//*** code specifique ici
|
||||
}
|
||||
else if(strncmp(e->fn, "vers", 4) == 0)
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
// renvoie la version du module/plugins
|
||||
if(param->type == VAR_DYNAMIC)
|
||||
dynLet(e, param, "1", 1); //*** version en alpha
|
||||
else if(param->type == VAR_NUMBER)
|
||||
param->num = NUM_UN; //*** version en numerique
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
if(param1 == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
if(param->type == VAR_NUMBER)
|
||||
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
|
||||
// renvoie la version du module/plugins
|
||||
if(param1->type == VAR_DYNAMIC)
|
||||
dynLet(e, param1, "1", 1); //*** version en alpha
|
||||
else if(param1->type == VAR_NUMBER)
|
||||
param1->num = NUM_UN; //*** version en numerique
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
}
|
||||
}
|
||||
else if(modFnIs(e, "error", 5))
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(param1 == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
if(param1->type == VAR_NUMBER)
|
||||
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
|
||||
else
|
||||
exc = EX_MODPARAM; // bad type of parameter
|
||||
}
|
||||
}
|
||||
/* ============================================================================================= */
|
||||
else if(strncmp(e->fn, "conn", 4) == 0)
|
||||
else if(modFnIs(e, "conn", 4))
|
||||
{
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
@@ -182,7 +196,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
}
|
||||
}
|
||||
/* ============================================================================================= */
|
||||
else if(strncmp(e->fn, "disc", 4) == 0)
|
||||
else if(modFnIs(e, "disc", 4))
|
||||
{
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
@@ -208,7 +222,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
}
|
||||
}
|
||||
/* ============================================================================================= */
|
||||
else if(strncmp(e->fn, "info", 4) == 0)
|
||||
else if(modFnIs(e, "info", 4))
|
||||
{
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
|
||||
+9
-9
@@ -221,7 +221,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------
|
||||
if(strncmp(e->fn, "read", 4) == 0)
|
||||
if(modFnIs(e, "read", 4))
|
||||
{
|
||||
// param<1> = no fichier ; param<2> = cle
|
||||
dynRemove(e, param, &p_etat->mTmp, cFM, DYN_TRUE);
|
||||
@@ -319,11 +319,11 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
return EX_DB_ELSE; // pas d'erreur : mettre le code pour "non trouve" ELSE
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "write", 4) == 0)
|
||||
else if(modFnIs(e, "write", 5))
|
||||
{
|
||||
//
|
||||
}
|
||||
else if(strncmp(e->fn, "open", 4) == 0)
|
||||
else if(modFnIs(e, "open", 4))
|
||||
{
|
||||
// param<1> = nom table ; si ok renvoie en retour param<1> = id fichier (indice du tableau)
|
||||
int lgSav = p_etat->mBase.mLg;
|
||||
@@ -376,7 +376,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
}
|
||||
dynSetLen(e, &p_etat->mBase, lgSav);
|
||||
}
|
||||
else if(strncmp(e->fn, "create", 5) == 0)
|
||||
else if(modFnIs(e, "create", 5))
|
||||
{
|
||||
// cree la table : param<1> nom ; modulo param<2> ; separateur param<3>
|
||||
fileHeader info;
|
||||
@@ -421,7 +421,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "close", 5) == 0)
|
||||
else if(modFnIs(e, "close", 5))
|
||||
{
|
||||
// param<1> = no fichier
|
||||
int pos = dynToNum(e, param, 0, 6);
|
||||
@@ -437,7 +437,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
// sinon, fichier deja ferme : RAS
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "setup", 5) == 0)
|
||||
else if(modFnIs(e, "setup", 5))
|
||||
{
|
||||
// sortir si mId deja present (!=0) : une base est deja ouverte
|
||||
// param<1> = repertoire de base => sa cle d'acces = mKey
|
||||
@@ -488,7 +488,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "init", 4) == 0)
|
||||
else if(modFnIs(e, "init", 4))
|
||||
{
|
||||
// si init deja fait, ras
|
||||
if(p_etat == NULL)
|
||||
@@ -502,7 +502,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
dynInit(e, &p_etat->mEntry, DYN_LGMIN);
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "end", 3) == 0)
|
||||
else if(modFnIs(e, "end", 3))
|
||||
{
|
||||
struct shmid_ds attrs = {0};
|
||||
// liberation specifique au module avant arret process
|
||||
@@ -534,7 +534,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
|
||||
memfree(e, p_etat);
|
||||
*etat = NULL;
|
||||
}
|
||||
else if(strncmp(e->fn, "vers", 4) == 0)
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
// renvoie la version du module/plugins
|
||||
dynLet(e, param, "100", 3); // version 1.00 ici
|
||||
|
||||
@@ -5,5 +5,7 @@ aide: (1,1,?)
|
||||
nombre: (1,9,0-9)
|
||||
ajouter: (1,1,#2B) ; +
|
||||
supprimer:(1,1,#2D) ; -
|
||||
ident: (1,1,#3A) (1,1,a-zA-Z_) (0,23,a-zA-Z0-9) ; :abcABC123
|
||||
ident: (1,1,#3A) (1,1,a-zA-Z_) (0,23,a-zA-Z0-9) ; :_abcABC123
|
||||
identnext:(1,1,#2E) (1,1,a-zA-Z) (0,23,a-zA-Z0-9) ; .abcABC123
|
||||
reste: (1,1,#00-#FF)
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
;
|
||||
; for background w process debugging
|
||||
; using shm_lib on buffer "dbg<pid>" for the debugged process
|
||||
; Usage: lw debug <pid2debug>
|
||||
;
|
||||
begin wdebug
|
||||
declare idProc, msg, pid, cmd, ret, capt, again, delay, debugging, signal
|
||||
declare OK, ERROR
|
||||
let debugging = @false
|
||||
let OK = 0
|
||||
let ERROR = neg(1)
|
||||
;
|
||||
sub WriteProcess(id, message, cr)
|
||||
invoke shm&set(id, message)
|
||||
let cr = OK
|
||||
except
|
||||
let cr = ERROR
|
||||
catch
|
||||
endsub
|
||||
;
|
||||
sub ReadProcess(message, cr)
|
||||
invoke shm&get(message)
|
||||
let cr = OK
|
||||
except
|
||||
let cr = ERROR
|
||||
catch
|
||||
endsub
|
||||
; ********************************************************
|
||||
;
|
||||
let pid = field(@arg, @currfm, 2)
|
||||
if pid = '' or type(pid) # @varnumber then
|
||||
let msg = 'Incorrect pid number (':pid:'), abort'
|
||||
echonl msg
|
||||
return
|
||||
endif
|
||||
;
|
||||
let idProc = 'dbg':pid
|
||||
let msg = 'Start debugging process ':pid
|
||||
echonl msg
|
||||
;
|
||||
loop
|
||||
let msg = 'Sending SIGUSR1 signal and wait 1 second'
|
||||
echonl msg
|
||||
let capt = ''
|
||||
let ret = 0
|
||||
let signal = 10
|
||||
invoke system&sendSignal(pid, signal)
|
||||
; now waiting for shm to init from signaled process
|
||||
let delay = 1
|
||||
invoke system&sleep(delay)
|
||||
;
|
||||
let msg = '%':@prog
|
||||
do WriteProcess(idProc, msg, ret)
|
||||
breakon ret = OK
|
||||
; retry ?
|
||||
let msg = 'Process ':pid:" don't respond to debug start message (":msg:"), try again (Y/N) ? "
|
||||
echo msg
|
||||
input again
|
||||
breakon again # 'y' and again # 'Y'
|
||||
endloop
|
||||
returnon ret # OK
|
||||
;
|
||||
; ok, we can debug background process now
|
||||
; 1. read prompt
|
||||
; 2. get command from user
|
||||
; 3. send command
|
||||
; 4. repeat from step 1
|
||||
let msg = "Ready for debuging... ('q' to end session)"
|
||||
echonl msg
|
||||
let delay = 0.1
|
||||
let debugging = @true
|
||||
loop
|
||||
do ReadProcess(msg, ret)
|
||||
breakon ret # OK or msg = '%'
|
||||
if msg # '' then
|
||||
echo msg
|
||||
loop
|
||||
let cmd = ''
|
||||
input cmd
|
||||
breakon cmd # ''
|
||||
endloop
|
||||
;
|
||||
do WriteProcess(idProc, cmd, ret)
|
||||
breakon ret # OK
|
||||
else
|
||||
invoke system&sleep(delay)
|
||||
endif
|
||||
endloop
|
||||
let msg = "End of debugging"
|
||||
echonl msg
|
||||
;
|
||||
except
|
||||
if debugging then
|
||||
let cmd = '%'
|
||||
do WriteProcess(idProc, cmd, ret)
|
||||
endif
|
||||
let msg = 'Exception ':@except
|
||||
echonl msg
|
||||
end
|
||||
@@ -23,28 +23,33 @@
|
||||
#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"
|
||||
#define sTM "\xFB"
|
||||
|
||||
#define DYN_OK 0 // attention, DYN_OK doit etre egal a 0 sinon des tests seront KO...
|
||||
#define DYN_ERR -1
|
||||
enum {
|
||||
DYN_OK = 0, // attention, DYN_OK doit etre egal a 0 sinon des tests seront KO...
|
||||
DYN_ERR = -1,
|
||||
|
||||
#define DYN_FALSE 0
|
||||
#define DYN_TRUE -1
|
||||
DYN_FALSE = 0,
|
||||
DYN_TRUE = -1,
|
||||
|
||||
#define DYN_LGNONE -1 // quand un parametre ne doit pas etre pris en compte, de type "lgChaine"
|
||||
#define DYN_NONE 0 // quand un parametre ne doit pas etre pris en compte, de type "numChamp/numSousChamp separateurChamp/SousChamp"
|
||||
DYN_LGNONE = -1, // quand un parametre ne doit pas etre pris en compte, de type "lgChaine"
|
||||
DYN_NONE = 0, // quand un parametre ne doit pas etre pris en compte, de type "numChamp/numSousChamp separateurChamp/SousChamp"
|
||||
|
||||
#define DYN_ALL 0 // toues les occurences (dynChange...)
|
||||
DYN_ALL = 0, // toues les occurences (dynChange...)
|
||||
|
||||
#define DYN_SORT_ASC 1
|
||||
#define DYN_SORT_DESC 2
|
||||
DYN_SORT_ASC = 1,
|
||||
DYN_SORT_DESC = 2,
|
||||
|
||||
DYN_NOTFOUND = -1, // quand index ne trouve pas
|
||||
DYN_NOTLOCATED = 0 // locate ne trouve pas
|
||||
};
|
||||
|
||||
/*typedef struct
|
||||
{
|
||||
@@ -65,83 +70,89 @@ typedef var Dynamic;
|
||||
si erreur de codage/lecture utf8, la norme est de le remplacer par le point de code \uFFFD (EF BF BD) et de continuer (à convertir en 3F ? par exemple en mono byte)
|
||||
*/
|
||||
|
||||
#include "apidecl.h"
|
||||
|
||||
/* ********************************************** */
|
||||
void NumberToSz(env * e, ent64s valeur, char * resultat, long * lg);
|
||||
char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
|
||||
char * Int32ToSz(ent32s valeur, long signe, long leftPad);
|
||||
long dynInit(env * e, Dynamic * this, long lgmax);
|
||||
long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
|
||||
void dynFree(env * e, Dynamic * this);
|
||||
void dynSetLen(env * e, Dynamic * this, long lg);
|
||||
WAPIDECL char * NumberToSz(env * e, ent64s valeur, char * resultat, ent64s * lg);
|
||||
WAPIDECL char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
|
||||
WAPIDECL char * Int32ToSz(ent32s valeur, long signe, long leftPad);
|
||||
WAPIDECL long dynInit(env * e, Dynamic * this, long lgmax);
|
||||
WAPIDECL long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
|
||||
WAPIDECL void dynFree(env * e, Dynamic * this);
|
||||
WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg);
|
||||
//long dynCarU8(env * e, Dynamic * this, long * pos);
|
||||
//long dynLgU8(env * e, Dynamic * this);
|
||||
long dynLengthUtf8(const char * p, long lg, int separator);
|
||||
long dynNextUtf8(char ** p, long lg, long * pos, char * carU8, int separator);
|
||||
long dynCtrl(env * e, Dynamic * this, long lg, long copier);
|
||||
long Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
|
||||
long UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
|
||||
void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
|
||||
void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
|
||||
long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
|
||||
long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
|
||||
long dynSetAsSz(env * e, Dynamic * this, char * chaine);
|
||||
long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
|
||||
long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
|
||||
long dynRead(env * e, Dynamic * this, char * fichier);
|
||||
long dynWrite(env * e, Dynamic * this, char * fichier);
|
||||
ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
|
||||
ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
|
||||
ent64s dynToNumber(env * e, Dynamic * this);
|
||||
long dynConvertError(env * e, Dynamic * this);
|
||||
long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
|
||||
long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
|
||||
long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
|
||||
long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
|
||||
long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
|
||||
long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
|
||||
long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
|
||||
ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
|
||||
long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
|
||||
ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
|
||||
ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
|
||||
long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
|
||||
long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
|
||||
long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
|
||||
long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
|
||||
long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
|
||||
long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
|
||||
long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
|
||||
void dynBegin(env * e, Dynamic * this);
|
||||
long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
|
||||
long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
|
||||
long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
long dynCountUtf8(env * e, Dynamic * this, char * caractere4, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
long dynSetSubstrUtf8(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
long dynSubstrUtf8(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
|
||||
long dynConvert(env * e, Dynamic * this, char * from, char * to);
|
||||
void dynReplace(env * e, Dynamic * this, char from, char to);
|
||||
long dynConvertUtf8(env * e, Dynamic * this, char * from, char * to);
|
||||
void dynErase(env * e, Dynamic * this, char * car);
|
||||
void dynEraseUtf8(env * e, Dynamic * this, char * car);
|
||||
long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
|
||||
long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
|
||||
long dynIndexSzUtf8(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
|
||||
long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
|
||||
long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
|
||||
long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
|
||||
long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
|
||||
long dynConvertHexaToLong(Dynamic * valeur);
|
||||
long dynConvertCharHexaToChar(char c1, char c2, char * c);
|
||||
long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg);
|
||||
long dynFmtUtf8(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char * filler, long lg);
|
||||
long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadrage, char filler, long lg);
|
||||
long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option);
|
||||
long dynTrimUtf8(env * e, Dynamic * this, Dynamic * resultat, char * car, long option);
|
||||
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);
|
||||
WAPIDECL void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
|
||||
WAPIDECL long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
|
||||
WAPIDECL long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
|
||||
WAPIDECL long dynSetAsSz(env * e, Dynamic * this, char * chaine);
|
||||
WAPIDECL long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
|
||||
WAPIDECL long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
|
||||
WAPIDECL long dynRead(env * e, Dynamic * this, char * fichier);
|
||||
WAPIDECL long dynWrite(env * e, Dynamic * this, char * fichier);
|
||||
WAPIDECL ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
|
||||
WAPIDECL ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
|
||||
WAPIDECL ent64s dynToNumber(env * e, Dynamic * this);
|
||||
WAPIDECL long dynConvertError(env * e, Dynamic * this);
|
||||
WAPIDECL long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
|
||||
WAPIDECL long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
|
||||
WAPIDECL long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
|
||||
WAPIDECL long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
|
||||
WAPIDECL ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
|
||||
WAPIDECL long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
|
||||
WAPIDECL ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
|
||||
WAPIDECL ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
|
||||
WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
|
||||
WAPIDECL long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
|
||||
WAPIDECL long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
|
||||
WAPIDECL long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
|
||||
WAPIDECL void dynBegin(env * e, Dynamic * this);
|
||||
WAPIDECL long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
|
||||
WAPIDECL long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
|
||||
WAPIDECL long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynCountUtf8(env * e, Dynamic * this, char * caractere4, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynSetSubstrUtf8(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL long dynSubstrUtf8(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
|
||||
WAPIDECL char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
|
||||
WAPIDECL long dynConvert(env * e, Dynamic * this, char * from, char * to);
|
||||
WAPIDECL void dynReplace(env * e, Dynamic * this, char from, char to);
|
||||
WAPIDECL long dynConvertUtf8(env * e, Dynamic * this, char * from, char * to);
|
||||
WAPIDECL void dynErase(env * e, Dynamic * this, char * car);
|
||||
WAPIDECL void dynEraseUtf8(env * e, Dynamic * this, char * car);
|
||||
WAPIDECL long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
|
||||
WAPIDECL long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
|
||||
WAPIDECL long dynIndexSzUtf8(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
|
||||
WAPIDECL long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
|
||||
WAPIDECL long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
|
||||
WAPIDECL long 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
|
||||
@@ -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 InitFcgi(env * e, modCtxFcgi * ctx);
|
||||
WAPIDECL void FreeFcgi(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}}
|
||||
|
||||
*/
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -20,359 +20,215 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
/* types de requete FCGI */
|
||||
#define FCGI_BEGIN_REQUEST 1
|
||||
#define FCGI_ABORT_REQUEST 2
|
||||
#define FCGI_END_REQUEST 3
|
||||
#define FCGI_PARAMS 4
|
||||
#define FCGI_STDIN 5
|
||||
#define FCGI_STDOUT 6
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
/* demande dans le BEGIN REQUEST */
|
||||
#define FCGI_RESPONDER 1
|
||||
#define FCGI_AUTHORIZER 2
|
||||
#define FCGI_FILTER 3
|
||||
#include "langage.h"
|
||||
#include "dynamic.h"
|
||||
#include "var.h"
|
||||
|
||||
/* code du "protocl status" lors du END REQUEST */
|
||||
#define FCGI_REQUEST_COMPLETE 0
|
||||
#define FCGI_CANT_MPX_CONN 1
|
||||
#define FCGI_OVERLOADED 2
|
||||
#define FCGI_UNKNOWN_ROLE 3
|
||||
#include "fcgi.h"
|
||||
|
||||
/* codes d'erreurs du module */
|
||||
#define WFC_OK 0 /* continuer a lire */
|
||||
#define WFC_ERR 1
|
||||
#define WFC_KEEPALIVE 2
|
||||
#define 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;
|
||||
#define MOD_VERSION 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)
|
||||
/* mettre ici les codes d'erreurs specifiques au module */
|
||||
/* codes a passer a la fonction setError */
|
||||
enum {
|
||||
EXMOD_FCGI_REQUEST_ERROR = 1,
|
||||
EXMOD_FCGI_RESPONSE_ERROR = 2,
|
||||
EXMOD_NB = 2
|
||||
};
|
||||
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
|
||||
char * descModErr[] = {
|
||||
"No error", // 0
|
||||
"Error in FCGI request",
|
||||
"Error making FCGI response"
|
||||
};
|
||||
/* ============================================================================================= */
|
||||
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
modEtat * p_etat;
|
||||
long exc = OK;
|
||||
/* init/end/vers/error sont obligatoires pour tout module */
|
||||
if(etat == NULL)
|
||||
return EX_MODPARAM;
|
||||
else
|
||||
return WFC_ERR; /* TODO pas de requete en cours */
|
||||
}
|
||||
|
||||
long getFcgiDataOut(env * e, Dynamic * msg)
|
||||
{
|
||||
if(fcgiReq.vers != 0 && fcgiReq.id != 0)
|
||||
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))
|
||||
{
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
long readFcgi(env * e, Dynamic * msg)
|
||||
{
|
||||
/* "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)
|
||||
{
|
||||
/* entete requete lue => prise en charge du message */
|
||||
if(msg->mLg < fcgiReq->lg)
|
||||
if(p_etat == NULL)
|
||||
{
|
||||
return WFC_OK; /* TODO message de la requete de longueur incorrecte : continuer a lire */
|
||||
}
|
||||
if(fcgiReq.req == FCGI_BEGIN_REQUEST)
|
||||
{
|
||||
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;
|
||||
}
|
||||
// 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_ERR; /* TODO role non pris en charge */
|
||||
p_etat = (modEtat *)(*etat);
|
||||
setError(p_etat, OK); // evite un warning de compil
|
||||
//*** code specifique ici
|
||||
InitFcgi(e, &p_etat->ctxFcgi);
|
||||
/* ============ here ============ */
|
||||
}
|
||||
}
|
||||
if(fcgiReq.req == FCGI_PARAMS)
|
||||
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
|
||||
}
|
||||
else if(modFnIs(e, "end", 3))
|
||||
{
|
||||
if(p_etat != NULL)
|
||||
{
|
||||
/* 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;)
|
||||
//*** code specifique ici
|
||||
FreeFcgi(e, &p_etat->ctxFcgi);
|
||||
/* ============ 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
|
||||
{
|
||||
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;
|
||||
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
|
||||
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
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*/
|
||||
var * paramModError = getParam(e, "modError", 8);
|
||||
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
|
||||
if(paramModError == 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 */
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
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, "getRequest", 10))
|
||||
{
|
||||
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
|
||||
/* get param in the right order */
|
||||
var * paramInput = getParam(e, "inputData", 9); // format FCGI
|
||||
var * paramContent = getParam(e, "content", 7); // message "clair"
|
||||
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
|
||||
{
|
||||
return WFC_ERR; /* TODO pas de requete en cours */
|
||||
if(paramReturn->type != VAR_NUMBER)
|
||||
var_let(e, paramReturn, &e->int_number, FALSE, FALSE);
|
||||
/* */
|
||||
long cr = ExtractMessage(e, &p_etat->ctxFcgi, paramInput);
|
||||
/* */
|
||||
p_etat->error = OK;
|
||||
if(cr == FCGI_REQUEST_AVAILABLE)
|
||||
dynSetAs(e, paramContent, &p_etat->ctxFcgi.dataIn);
|
||||
else if(cr == FCGI_REQUEST_ERROR)
|
||||
p_etat->error = EXMOD_FCGI_REQUEST_ERROR; /* A REVOIR !! */
|
||||
/* */
|
||||
paramReturn->num = cr * NUM_FACTEUR;
|
||||
}
|
||||
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)
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
else if(modFnIs(e, "setResponse", 11))
|
||||
{
|
||||
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
|
||||
/* get param in the right order */
|
||||
var * paramOutput = getParam(e, "outputData", 9); // format FCGI
|
||||
var * paramContent = getParam(e, "content", 7); // reponse "clair"
|
||||
var * paramReturn = getParam(e, "returnCode", 10);
|
||||
if(paramOutput == NULL || paramContent == NULL || paramReturn == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else if(paramOutput->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
return WFC_ERR; /* TODO pas de requete en cours */
|
||||
number retCode;
|
||||
if( ! var_conv_num(e, paramReturn, &retCode))
|
||||
exc = setError(p_etat, EX_MODPARAM);
|
||||
else
|
||||
{
|
||||
p_etat->error = OK;
|
||||
long cr = MakeResponse(e, &p_etat->ctxFcgi, retCode / NUM_FACTEUR, paramContent);
|
||||
/* */
|
||||
if(cr == OK)
|
||||
dynSetAs(e, paramOutput, &p_etat->ctxFcgi.dataOut);
|
||||
else
|
||||
p_etat->error = EXMOD_FCGI_RESPONSE_ERROR; /* A REVOIR !! */
|
||||
}
|
||||
}
|
||||
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 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);
|
||||
/* verifier si keepalive est dedans, sinon l'ajouter */
|
||||
dynSetAs(e, paramHeader, &p_etat->ctxFcgi.param);
|
||||
}
|
||||
}
|
||||
/* ============================================================================================= */
|
||||
else
|
||||
{
|
||||
return WFC_ERR; /* TODO type requete non prise en charge */
|
||||
exc = EX_MODFUNC; /* unsupported function */
|
||||
}
|
||||
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"
|
||||
*
|
||||
*/
|
||||
+386
@@ -0,0 +1,386 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / 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 InitFcgi(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 FreeFcgi(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;
|
||||
//
|
||||
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"
|
||||
*/
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -25,225 +25,317 @@
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef UNIX
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include "windows.h" // pour les fonctions FindFile...
|
||||
#endif
|
||||
|
||||
#include "langage.h"
|
||||
#include "dynamic.h"
|
||||
#include "var.h"
|
||||
|
||||
/* ============================================================================================= */
|
||||
#ifdef UNIX
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include "windows.h" // pour les fonctions FindFile...
|
||||
#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 */
|
||||
#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"
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
|
||||
modEtat * p_etat;
|
||||
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 */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
/* 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(strncmp(e->fn, "end", 3) == 0)
|
||||
else if(modFnIs(e, "end", 3))
|
||||
{
|
||||
//*** code specifique ici
|
||||
// liberation specifique au module avant arret process
|
||||
if(p_etat != NULL)
|
||||
{
|
||||
//*** code specifique ici
|
||||
/* ============ here ============ */
|
||||
// liberation du module avant arret process
|
||||
memfree(e, p_etat);
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "vers", 4) == 0)
|
||||
else if(p_etat == NULL)
|
||||
{
|
||||
// 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;
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
exc = EX_MODETAT;
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
// 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(strncmp(e->fn, "create", 6) == 0)
|
||||
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(strncmp(e->fn, "get", 3) == 0)
|
||||
{
|
||||
/* 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(strncmp(e->fn, "set", 3) == 0)
|
||||
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(strncmp(e->fn, "size", 4) == 0)
|
||||
else if(modFnIs(e, "get", 3))
|
||||
{
|
||||
/* 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 * paramContent = getParam(e, "content", 7);
|
||||
/* utilisation de dynRead qui fait le travail */
|
||||
if(paramPath == NULL || paramContent == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(modFnIs(e, "size", 4))
|
||||
{
|
||||
/* 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "dir", 3) == 0)
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* */
|
||||
@@ -252,32 +344,35 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
|
||||
#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;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -27,46 +27,36 @@
|
||||
|
||||
#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,free,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
|
||||
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
|
||||
*/
|
||||
struct {
|
||||
ent16 blank,comment,begin,background,library,end,except,throw,catch,include;
|
||||
ent16 sub,endsub,if_,then,else_,elseif,endif,do_,call,invoke;
|
||||
ent16 return_,returnon,loop,endloop,foreach,in,like,endfor,break_,breakon;
|
||||
ent16 continue_,continueon,nop,part,echonl,echo,input,declare,let,delet;
|
||||
ent16 new,class,this,parent,free,precision,setsep,int_,frac,abs;
|
||||
ent16 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 new,class,this,parent,hold,precision,setsep,int_,frac,abs;
|
||||
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)
|
||||
@@ -119,7 +109,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
|
||||
r.class = rg(e, regles, "class", tmp);
|
||||
r.this = rg(e, regles, "this", tmp);
|
||||
r.parent = rg(e, regles, "parent", tmp);
|
||||
r.free = rg(e, regles, "free", tmp);
|
||||
r.hold = rg(e, regles, "hold", tmp);
|
||||
r.precision = rg(e, regles, "precision", tmp);
|
||||
r.setsep = rg(e, regles, "setsep", tmp);
|
||||
r.int_ = rg(e, regles, "int", tmp);
|
||||
@@ -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,21 +170,123 @@ 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);
|
||||
}
|
||||
|
||||
static void formatage(Dynamic * s, Dynamic * f, int type)
|
||||
enum {
|
||||
TAB_COUNT = 3,
|
||||
COMMENT_EOL = 8
|
||||
};
|
||||
|
||||
static void formatage_asm(Dynamic * s, Dynamic * f)
|
||||
{
|
||||
// s : source ; f : source apres formatage, type : 1 w, 2 pcode
|
||||
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)
|
||||
{
|
||||
// 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 */
|
||||
//#define nreg(x) ((x)*2 > token.mLg ? 0 : *(ent16 *)(token.mPtr + (x)*2 - 2))
|
||||
#define ntok(x) dynExtractSubFieldAsNumber(&e, &valex, 2, x, &tmp)
|
||||
//
|
||||
#define TAB_COUNT 3
|
||||
#define COMMENT_EOL 8
|
||||
//#define TAB_COUNT 3
|
||||
//#define COMMENT_EOL 8
|
||||
//
|
||||
Dynamic trav, tmp, lig; /* variables de travail */
|
||||
Dynamic regles; /* regles lex */
|
||||
@@ -236,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()
|
||||
@@ -314,7 +409,7 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
|
||||
//if(tok2 != r.comment)
|
||||
// pos_comment = -1;
|
||||
}
|
||||
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 10 (par exemple), >= position actuelle
|
||||
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 8, >= position actuelle
|
||||
// + formatage debut de ligne
|
||||
if(pos_comment == -1)
|
||||
{
|
||||
@@ -326,7 +421,8 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
|
||||
}
|
||||
else
|
||||
{
|
||||
dynSubstr(&e, &trav, &lig, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
|
||||
dynSubstr(&e, &trav, &tmp, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
|
||||
dynTrim(&e, &tmp, &lig, ' ', 2);
|
||||
#ifdef WINLIB
|
||||
dynSubstr(&e, &trav, &tmp, pos_comment - 1, ((intptr_t)(trav.mPtr)) - pos_comment, 1, DYN_NONE, 10, DYN_NONE);
|
||||
#else
|
||||
@@ -402,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");
|
||||
@@ -420,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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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, ®les, NULL) != DYN_OK)
|
||||
if(lire_regles_lex(&e, ®les, "lexlex") != DYN_OK)
|
||||
ret = -3;
|
||||
}
|
||||
if(ret == 0)
|
||||
{
|
||||
init_reg(&e, ®les, &elem1);
|
||||
//printf("commentaire : %ld nomregle : %ld\n", r.commentaire, r.nomregle);
|
||||
init_reg_lex(&e, ®les, &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, ®les, &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);
|
||||
|
||||
@@ -25,9 +25,19 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "langage.h"
|
||||
#include "dynamic.h"
|
||||
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
/* met a jour le minimum de <env> pour pouvoir utiliser <dynamic.h> sans erreur... */
|
||||
void init_env(env * e)
|
||||
WAPIDECL void init_env(env * e)
|
||||
{
|
||||
int i,j,k;
|
||||
/* endianess */
|
||||
@@ -55,7 +65,7 @@ void init_env(env * e)
|
||||
e->sep_subfield = '\xFD'; // cVM
|
||||
}
|
||||
|
||||
char * copy_nom(env * e, const char * s)
|
||||
WAPIDECL char * copy_nom(env * e, const char * s)
|
||||
{
|
||||
e->nom64[0] = 0;
|
||||
e->nom64[1] = 0;
|
||||
@@ -66,7 +76,26 @@ char * copy_nom(env * e, const char * s)
|
||||
return e->nom;
|
||||
}
|
||||
|
||||
int modFnIs(env * e, const char * fn, int lg)
|
||||
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
|
||||
ent64 f[3];
|
||||
@@ -81,7 +110,7 @@ int modFnIs(env * e, const char * fn, int lg)
|
||||
/* fonctions wrapper au cas ou on aurait besoin de ne plus utiliser certaines */
|
||||
/* fonctions standards (malloc, etc.) */
|
||||
|
||||
void * memalloc(env * e, ent64 taille)
|
||||
WAPIDECL void * memalloc(env * e, ent64 taille)
|
||||
{
|
||||
void * ptr;
|
||||
taille += sizeof(ent64);
|
||||
@@ -109,7 +138,7 @@ void * memalloc(env * e, ent64 taille)
|
||||
}
|
||||
}
|
||||
|
||||
void memfree(env * e, void * ptr)
|
||||
WAPIDECL void memfree(env * e, void * ptr)
|
||||
{
|
||||
if(ptr != NULL)
|
||||
{
|
||||
@@ -129,7 +158,7 @@ void memfree(env * e, void * ptr)
|
||||
}
|
||||
}
|
||||
|
||||
void memcopie(void * dst, void * src, long nb)
|
||||
WAPIDECL void memcopie(void * dst, void * src, long nb)
|
||||
{
|
||||
if(dst == src || nb <= 0)
|
||||
return;
|
||||
@@ -147,7 +176,55 @@ void memcopie(void * dst, void * src, long nb)
|
||||
// for (char *p=src, *q=dst; --n>=0; ) q[n]=p[n]; // fin au debut
|
||||
}
|
||||
|
||||
void hex(pointeur ch, int lg)
|
||||
WAPIDECL void dynPrintfSz(env * e, const char * format, char * valeur)
|
||||
{
|
||||
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
|
||||
if(valeur)
|
||||
dynChange(e, &e->printf, PRINTF_MARK, valeur, DYN_ALL);
|
||||
}
|
||||
|
||||
WAPIDECL void dynPrintfInt64(env * e, const char * format, ent64s valeur, long nb)
|
||||
{
|
||||
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
|
||||
dynChange(e, &e->printf, PRINTF_MARK, Int64ToSz(e, valeur, DYN_TRUE, nb), DYN_ALL);
|
||||
}
|
||||
|
||||
WAPIDECL void dynPrintfHex(env * e, const char * format, ent64 valeur, long nb)
|
||||
{
|
||||
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
||||
char conv[17] = "0000000000000000";
|
||||
conv[16] = 0;
|
||||
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
|
||||
int i;
|
||||
for(i = 15; i >=0 && valeur != 0; i--, valeur /= 16)
|
||||
conv[i] = hex[valeur % 16];
|
||||
//
|
||||
if(nb > 0 && nb < 17)
|
||||
nb = 16 - nb;
|
||||
else
|
||||
nb = i + 1;
|
||||
dynChange(e, &e->printf, PRINTF_MARK, conv + nb, DYN_ALL);
|
||||
}
|
||||
|
||||
WAPIDECL void dynPrintfConcatHexSz(env * e, char * valeur, long lg)
|
||||
{
|
||||
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
||||
char car[3] = {0};
|
||||
for(long i = 0; i < lg; i++)
|
||||
{
|
||||
car[0] = hex[((unsigned char)valeur[i]) >> 4];
|
||||
car[1] = hex[((unsigned char)valeur[i]) & 15];
|
||||
dynConcatSz(e, &e->printf, car, 2);
|
||||
if(i % 32 == 31 && i < lg - 1)
|
||||
dynConcatSz(e, &e->printf, "\n ", 4);
|
||||
else if(i % 8 == 7 && i < lg - 1)
|
||||
dynConcatSz(e, &e->printf, " | ", 3);
|
||||
else
|
||||
dynConcatSz(e, &e->printf, " ", 1);
|
||||
}
|
||||
}
|
||||
|
||||
WAPIDECL void hex(pointeur ch, int lg)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
@@ -167,7 +244,7 @@ void hex(pointeur ch, int lg)
|
||||
printf(" > %s\n", a);
|
||||
}
|
||||
|
||||
void hex2(char * ch, int lg, int nbpl)
|
||||
WAPIDECL void hex2(char * ch, int lg, int nbpl)
|
||||
{
|
||||
int i;
|
||||
char c;
|
||||
@@ -210,12 +287,18 @@ void hex2(char * ch, int lg, int nbpl)
|
||||
printf(" (%6d) %s\n", i, a);
|
||||
}
|
||||
|
||||
void hex3(const char * p, long lg)
|
||||
WAPIDECL void hex3(const char * p, long lg)
|
||||
{
|
||||
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
||||
// affiche en hexa la chaine sur une ligne
|
||||
printf("=> ");
|
||||
for(long i = 0; i < lg; i++)
|
||||
{
|
||||
printf("%c%c ", hex[((unsigned char)p[i]) >> 4], hex[((unsigned char)p[i]) & 15]);
|
||||
if(i % 32 == 31 && i < lg - 1)
|
||||
printf("\n ");
|
||||
else if(i % 8 == 7 && i < lg - 1)
|
||||
printf(" | ");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -23,23 +23,32 @@
|
||||
#ifndef GLOBAL_H
|
||||
#define GLOBAL_H
|
||||
|
||||
#include "apidecl.h"
|
||||
|
||||
void init_env(env * e);
|
||||
WAPIDECL void init_env(env * e);
|
||||
|
||||
char * copy_nom(env * e, const char * s);
|
||||
int modFnIs(env * e, const char * fn, int lg);
|
||||
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);
|
||||
|
||||
/* ************************************************************************** */
|
||||
/* fonctions wrapper au cas ou on aurait besoin de ne plus utiliser certaines */
|
||||
/* fonctions standards (malloc, etc.) */
|
||||
|
||||
void * memalloc(env * e, ent64 taille);
|
||||
void memfree(env * e, void * ptr);
|
||||
void memcopie(void * dst, void * src, long nb);
|
||||
WAPIDECL void * memalloc(env * e, ent64 taille);
|
||||
WAPIDECL void memfree(env * e, void * ptr);
|
||||
WAPIDECL void memcopie(void * dst, void * src, long nb);
|
||||
|
||||
void hex(pointeur ch, int lg);
|
||||
void hex2(char * ch, int lg, int nbpl);
|
||||
void hex3(const char * p, long lg);
|
||||
#define PRINTF_MARK "\1"
|
||||
WAPIDECL void dynPrintfSz(env * e, const char * format, char * valeur);
|
||||
WAPIDECL void dynPrintfInt64(env * e, const char * format, ent64s valeur, long nb);
|
||||
WAPIDECL void dynPrintfHex(env * e, const char * format, ent64 valeur, long nb);
|
||||
WAPIDECL void dynPrintfConcatHexSz(env * e, char * valeur, long lg); // equiv hex3
|
||||
|
||||
WAPIDECL void hex(pointeur ch, int lg);
|
||||
WAPIDECL void hex2(char * ch, int lg, int nbpl);
|
||||
WAPIDECL void hex3(const char * p, long lg);
|
||||
|
||||
/* ************************************ */
|
||||
#endif
|
||||
@@ -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);
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -25,393 +25,220 @@
|
||||
#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(char * entree, ent64 longueur, char * 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;
|
||||
unsigned char L = 0, T;
|
||||
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[j++] = carhex[buffer[i] / 16];
|
||||
sortie[j++] = carhex[buffer[i] % 16];
|
||||
}
|
||||
sortie[j] = 0;
|
||||
}
|
||||
|
||||
static void majMD4(unsigned int * md4, unsigned int * 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 = (unsigned char *)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;
|
||||
}
|
||||
|
||||
void encodageMD4(char * entree, ent64 longueur, char * 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;
|
||||
*(ent64 *)lg = (ent64)longueur * 8;
|
||||
/* */
|
||||
while(longueur >= 64)
|
||||
{
|
||||
majMD4(md4, (unsigned int *)entree);
|
||||
entree += 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, entree, 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, (unsigned int *)buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 2 derniers blocs */
|
||||
majMD4(md4, (unsigned int *)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, (unsigned int *)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[j] = carhex[buffer[0]/16];
|
||||
sortie[j+1] = carhex[buffer[0]%16];
|
||||
/* */
|
||||
buffer[0] = md4[i] & 255;
|
||||
md4[i] >>= 8;
|
||||
sortie[j+2] = carhex[buffer[0]/16];
|
||||
sortie[j+3] = carhex[buffer[0]%16];
|
||||
/* */
|
||||
buffer[0] = md4[i] & 255;
|
||||
md4[i] >>= 8;
|
||||
sortie[j+4] = carhex[buffer[0]/16];
|
||||
sortie[j+5] = carhex[buffer[0]%16];
|
||||
/* */
|
||||
buffer[0] = md4[i] & 255;
|
||||
sortie[j+6] = carhex[buffer[0]/16];
|
||||
sortie[j+7] = carhex[buffer[0]%16];
|
||||
}
|
||||
sortie[32] = 0;
|
||||
}
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
modEtat * p_etat;
|
||||
long exc = OK;
|
||||
// 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 */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
/* 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(strncmp(e->fn, "end", 3) == 0)
|
||||
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(strncmp(e->fn, "vers", 4) == 0)
|
||||
else if(p_etat == NULL)
|
||||
{
|
||||
// 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;
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
exc = EX_MODETAT;
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
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(strncmp(e->fn, "MD2", 3) == 0)
|
||||
else if(modFnIs(e, "MD2", 3))
|
||||
{
|
||||
p_etat->error = 0;
|
||||
// pour les vars en sortie, forcer le chgt de type si besoin ?
|
||||
if(param1->type != VAR_DYNAMIC)
|
||||
/* 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(param2->type != VAR_DYNAMIC)
|
||||
else if(paramPlaintext->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
encodageMD2(param1->mPtr, param1->lg, param2->mPtr);
|
||||
if(paramHashedText->type != VAR_DYNAMIC)
|
||||
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
|
||||
encodageMD2(e, paramPlaintext, paramHashedText);
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "MD4", 3) == 0)
|
||||
else if(modFnIs(e, "MD4", 3))
|
||||
{
|
||||
p_etat->error = 0;
|
||||
// pour les vars en sortie, forcer le chgt de type si besoin ?
|
||||
if(param1->type != VAR_DYNAMIC)
|
||||
/* 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(param2->type != VAR_DYNAMIC)
|
||||
else if(paramPlaintext->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
encodageMD4(param1->mPtr, param1->lg, param2->mPtr);
|
||||
if(paramHashedText->type != VAR_DYNAMIC)
|
||||
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
|
||||
encodageMD4(e, paramPlaintext, paramHashedText);
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(modFnIs(e, "MD5", 3))
|
||||
{
|
||||
/* 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);
|
||||
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
@@ -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);
|
||||
}
|
||||
+261
-21
@@ -27,15 +27,64 @@
|
||||
#include "langage.h"
|
||||
#include "var.h"
|
||||
#include "hashtable.h"
|
||||
#include "dynamic.h"
|
||||
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
// =============== PRIVATE ========================================================================
|
||||
static 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++;
|
||||
@@ -60,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
|
||||
}
|
||||
@@ -74,7 +123,7 @@ static entry * calc_entry(char * val, var * varht)
|
||||
|
||||
// =============== PUBLIC ========================================================================
|
||||
|
||||
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
|
||||
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
|
||||
{
|
||||
/* READ renvoi le ptr sur la var (ne fait pas une copie de la var)
|
||||
WRITE copie la var (si pas trouve ou trouve mais pointeurs differents)
|
||||
@@ -88,7 +137,13 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
|
||||
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) | */
|
||||
@@ -119,17 +174,19 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
|
||||
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;
|
||||
}
|
||||
@@ -149,7 +206,7 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
|
||||
{
|
||||
*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 */
|
||||
@@ -172,16 +229,57 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
var * hashtable_lastitemwritten(var * varht)
|
||||
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;
|
||||
}
|
||||
|
||||
void hashtable_select(env * e, var * varht)
|
||||
WAPIDECL void hashtable_select(env * e, var * varht)
|
||||
{
|
||||
/* les 4 variables necessaires seront mises dans le groupe 0, premiere entree (celle servant au chainage) */
|
||||
/* dans la variable (content, inutilise) : */
|
||||
@@ -197,10 +295,11 @@ void hashtable_select(env * e, var * varht)
|
||||
pvar->ptr = (pointeur)(pentry+1); /* pentry */
|
||||
}
|
||||
|
||||
int hashtable_next(env * e, var * varht, char * nom, var ** v)
|
||||
WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v)
|
||||
{
|
||||
var * pvar;
|
||||
entry * pentry;
|
||||
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++)
|
||||
{
|
||||
@@ -236,7 +335,7 @@ int hashtable_next(env * e, var * varht, char * nom, var ** v)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void hashtable_free_ovf(env *e, var * varht)
|
||||
WAPIDECL void hashtable_free_ovf(env *e, var * varht)
|
||||
{
|
||||
/* libere les overflow de la hash table */
|
||||
/* pour chaque entree, chainage avant puis liberation en revenant en arriere */
|
||||
@@ -259,7 +358,7 @@ void hashtable_free_ovf(env *e, var * varht)
|
||||
/* reste a liberer le bloc primaire de la hashtable */
|
||||
}
|
||||
|
||||
void hashtable_clear(env * e, var * varht)
|
||||
WAPIDECL void hashtable_clear(env * e, var * varht)
|
||||
{
|
||||
var * pvar;
|
||||
int suivrepar = TRUE;
|
||||
@@ -271,11 +370,11 @@ 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);
|
||||
}
|
||||
|
||||
long hashtable_count(env *e, var * varht)
|
||||
WAPIDECL long hashtable_count(env *e, var * varht)
|
||||
{
|
||||
long nb = 0;
|
||||
var * pvar;
|
||||
@@ -284,11 +383,68 @@ 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;
|
||||
}
|
||||
|
||||
void hashtable_printdebug(env * e, var * varht, int detail)
|
||||
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 */
|
||||
entry * pchain; /* pointe sur la premiere du groupe, servant au chainage */
|
||||
@@ -301,9 +457,18 @@ 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;
|
||||
printf("hashtable modulo=%lld separateur=%lld (n=%lld)\n", varht->modulo, varht->separateur, varht->separateur/sizeof(entry));
|
||||
if(e->demon)
|
||||
{
|
||||
dynPrintfInt64(e, "hashtable modulo=" PRINTF_MARK " separateur=", varht->modulo, 0);
|
||||
dynPrintfInt64(e, PRINTF_MARK " (n=", varht->separateur, 0);
|
||||
dynPrintfInt64(e, PRINTF_MARK ")\n", varht->separateur/sizeof(entry), 0);
|
||||
}
|
||||
else
|
||||
printf("hashtable modulo=%lld separateur=%lld (n=%lld)\n", varht->modulo, varht->separateur, varht->separateur/sizeof(entry));
|
||||
/* */
|
||||
occ = 0;
|
||||
tot = 0;
|
||||
@@ -341,7 +506,7 @@ void hashtable_printdebug(env * e, var * varht, int detail)
|
||||
else
|
||||
printf("%c", e->var_car[pentry->content.type % 10]);
|
||||
/* */
|
||||
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, "_class", 6) == 0 && ! ptrClass)
|
||||
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, GUV_CLASS, 6) == 0 && ! ptrClass)
|
||||
ptrClass = pentry->content.mPtr;
|
||||
/* */
|
||||
occ += sizeof(entry);
|
||||
@@ -355,8 +520,83 @@ void hashtable_printdebug(env * e, var * varht, int detail)
|
||||
pchain = (entry *)((ent64)pchain_first + varht->separateur);
|
||||
}
|
||||
if(ptrClass)
|
||||
printf("_class : %s\n", ptrClass);
|
||||
{
|
||||
dynLet(e, &e->tmp_dynamic, ptrClass, DYN_LGNONE);
|
||||
dynReplace(e, &e->tmp_dynamic, cFM, ':');
|
||||
printf("%s %s\n", GUV_CLASS, e->tmp_dynamic.mPtr);
|
||||
}
|
||||
printf("taille totale=%lld, occupee=%lld (taux %lld%%), nb item=%lld\n", tot, occ, occ * 100 / tot, nb);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
+15
-8
@@ -23,15 +23,22 @@
|
||||
#ifndef HASHTABLE_H
|
||||
#define HASHTABLE_H
|
||||
|
||||
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
|
||||
void hashtable_select(env * e, var * varht);
|
||||
int hashtable_next(env * e, var * varht, char * nom, var ** v);
|
||||
void hashtable_free_ovf(env *e, var * varht);
|
||||
void hashtable_clear(env *e, var * varht);
|
||||
long hashtable_count(env *e, var * varht);
|
||||
var * hashtable_lastitemwritten(var * varht);
|
||||
#include "apidecl.h"
|
||||
|
||||
void hashtable_printdebug(env * e, var * varht, int detail);
|
||||
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
|
||||
WAPIDECL void hashtable_select(env * e, var * varht);
|
||||
WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v);
|
||||
WAPIDECL void hashtable_free_ovf(env *e, var * varht);
|
||||
WAPIDECL void hashtable_clear(env *e, var * varht);
|
||||
WAPIDECL long hashtable_count(env *e, var * varht);
|
||||
WAPIDECL var * hashtable_lastitemwritten(var * varht);
|
||||
WAPIDECL 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
|
||||
@@ -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);
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -28,7 +28,7 @@ void instr_unassemble(env * e, pointeur debutBin, ent64 nolig)
|
||||
/* special 2 bytes w opcode */
|
||||
case IN_COMP:
|
||||
d1 = lire8(p);
|
||||
if(d1 < CMP_EQ || d1 > CMP_NOT)
|
||||
if(d1 < CMP_EQ || d1 > CMP_FOR)
|
||||
printf("??? (%d)", d1);
|
||||
else
|
||||
{
|
||||
@@ -66,13 +66,20 @@ 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:
|
||||
case IN_PIDH:
|
||||
case IN_PHDO:
|
||||
case IN_PIDO:
|
||||
case IN_PHDN:
|
||||
case IN_PIDN:
|
||||
case IN_PHDV:
|
||||
case IN_PIDV:
|
||||
case IN_PVHD:
|
||||
case IN_PVID:
|
||||
case IN_DEXH:
|
||||
case IN_DEXI:
|
||||
case IN_DESH:
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
/* ************************************ */
|
||||
/* AJOUT D'UNE INSTRUCTION
|
||||
- instr.h : ci-dessous, 2 constantes + ajout a libInstr
|
||||
- instr.c : ajout constante, si besoin, dans instr_unassemble
|
||||
- langage.c : ajout dans le tableau de function instr + dans le commentaire en dessous,
|
||||
ajouter la function instr_xxx
|
||||
- assembler.c : ajout switch de la function assembler,
|
||||
@@ -38,16 +39,16 @@
|
||||
char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW" "PART" "RETN"
|
||||
"CALL" "PARM" "SUBR" "COMP" "JMPF" "JMPT" "ADDN" "SBCN" "MULN" "DIVN"
|
||||
"INTE" "FRAC" "NEGN" "ABSN" "MODL" "PSHC" "PSHV" "POPV" "PVAR" "PVAH"
|
||||
"WRIT" "WRLN" "DSET" "DEXV" "DCMP" "DSTO" "VLET" "DCAT" "DTON" "NTOD"
|
||||
"WRIT" "WRLN" "DSET" "DEXV" "DCMP" "DSTO" "LETV" "DCAT" "DTON" "NTOD"
|
||||
"DELE" "HLET" "CLAS" "NLET" "INCL" "PNAM" "PSH0" "PSH1" "PSH2" "PSH3"
|
||||
"PSH4" "PSH5" "PSH6" "PSH7" "PSH8" "PSH9" "PSHA" "PROG" "BACK" "CLIB"
|
||||
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPSH" "RETT"
|
||||
"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" "xxxx" "xxxx" "xxxx" "xxxx" /* 110-119 */
|
||||
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
|
||||
"DESH" "DESI" "DEZV" "DEZH" "DEZI" "SDBG" "PHDN" "PIDN" "SADV" "VLET" /* 110-119 */
|
||||
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "SSRC" "SSCS" "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"
|
||||
@@ -60,9 +61,9 @@ 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[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
|
||||
char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "FOR"};
|
||||
|
||||
#define IS_VERS "\x00"
|
||||
#define IN_VERS 0
|
||||
@@ -139,8 +140,8 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
|
||||
#define IN_DCMP 34
|
||||
#define IS_DSTO "\x23"
|
||||
#define IN_DSTO 35
|
||||
#define IS_VLET "\x24"
|
||||
#define IN_VLET 36
|
||||
#define IS_LETV "\x24"
|
||||
#define IN_LETV 36
|
||||
#define IS_DCAT "\x25"
|
||||
#define IN_DCAT 37
|
||||
#define IS_DTON "\x26"
|
||||
@@ -183,10 +184,10 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
|
||||
#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
|
||||
|
||||
@@ -206,8 +207,8 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
|
||||
#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
|
||||
|
||||
@@ -307,13 +308,41 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
|
||||
#define IN_DEZI 114
|
||||
#define IS_SDBG "\x73"
|
||||
#define IN_SDBG 115
|
||||
#define IS_PHDN "\x74"
|
||||
#define IN_PHDN 116
|
||||
#define IS_PIDN "\x75"
|
||||
#define IN_PIDN 117
|
||||
#define IS_SADV "\x76"
|
||||
#define IN_SADV 118
|
||||
#define IS_VLET "\x77"
|
||||
#define IN_VLET 119
|
||||
#define IS_PHDV "\x78"
|
||||
#define IN_PHDV 120
|
||||
#define IS_PIDV "\x79"
|
||||
#define IN_PIDV 121
|
||||
#define IS_HCOU "\x7A"
|
||||
#define IN_HCOU 122
|
||||
#define IS_PVHD "\x7B"
|
||||
#define IN_PVHD 123
|
||||
#define IS_PVID "\x7C"
|
||||
#define IN_PVID 124
|
||||
#define IS_SSRC "\x7D"
|
||||
#define IN_SSRC 125
|
||||
#define IS_SSCS "\x7E"
|
||||
#define IN_SSCS 126
|
||||
#define IS_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"
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "langage.h"
|
||||
@@ -29,32 +51,34 @@ typedef struct
|
||||
|
||||
/* mettre ici les codes d'erreurs specifiques au module */
|
||||
/* codes a passer a la fonction setError */
|
||||
#define EXMODJSON_MEM 106
|
||||
#define EXMODJSON_DECODE_INCORRECT_CHAR 101
|
||||
#define EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED 102
|
||||
#define EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED 103
|
||||
#define EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED 104
|
||||
#define EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER 105
|
||||
#define EXMODJSON_DECODE_UNTERMINATED_STRING 107
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT 108
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY 109
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_KEY 110
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_VALUE 111
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT 112
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT 113
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY 114
|
||||
#define EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON 115
|
||||
enum {
|
||||
EXMODJSON_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
|
||||
};
|
||||
|
||||
/*
|
||||
Le decodage a besoin de mEncodeCle mEncodeValeur et la position de l'erreur si erreur (3 parametres ; en entree la position le flag "NoDQuote"). L'erreur est le code retour.
|
||||
L'encodage a besoin de mEncode, mId, flag NoDQuote (3 parametres)
|
||||
*/
|
||||
|
||||
int jsonInit(env * e, modContextJson * ctx);
|
||||
int jsonEnd(env * e, modContextJson * ctx);
|
||||
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
|
||||
int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
|
||||
int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
|
||||
WAPIDECL int jsonInit(env * e, modContextJson * ctx);
|
||||
WAPIDECL int jsonEnd(env * e, modContextJson * ctx);
|
||||
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * 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);
|
||||
|
||||
/*
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -27,151 +27,203 @@
|
||||
|
||||
#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
|
||||
|
||||
#ifndef UNIX
|
||||
/* 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 */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
|
||||
modEtat * p_etat;
|
||||
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 */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
|
||||
if(modFnIs(e, "init", 4))
|
||||
{
|
||||
// alloc ptr sur zone memoire pour memoriser l'etat du module
|
||||
*etat = memalloc(e, sizeof(modEtat));
|
||||
if(*etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else
|
||||
{
|
||||
p_etat = (modEtat *)(*etat);
|
||||
p_etat->error = 0;
|
||||
//*** code specifique ici
|
||||
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "end", 3) == 0)
|
||||
{
|
||||
//*** code specifique ici
|
||||
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
|
||||
// liberation specifique au module avant arret process
|
||||
if(p_etat != NULL)
|
||||
memfree(e, p_etat);
|
||||
}
|
||||
else if(strncmp(e->fn, "vers", 4) == 0)
|
||||
{
|
||||
if(param1 == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
// renvoie la version du module/plugins
|
||||
if(param1->type == VAR_DYNAMIC)
|
||||
dynLet(e, param1, "1", 1); //*** version en alpha
|
||||
else if(param1->type == VAR_NUMBER)
|
||||
param1->num = NUM_UN; //*** version en numerique
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(param1 == 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
|
||||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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; // bad type of parameter
|
||||
{
|
||||
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(strncmp(e->fn, "decode", 6) == 0)
|
||||
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))
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
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))
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
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 if(strncmp(e->fn, "print", 5) == 0)
|
||||
{
|
||||
if(param1 == NULL || param2 == NULL || param3 == NULL)
|
||||
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));
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "treeFetch", 9) == 0)
|
||||
{
|
||||
if(param1 == NULL || param2 == NULL)
|
||||
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));
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else
|
||||
{
|
||||
exc = EX_MODFUNC; // fonction non prise en charge
|
||||
exc = EX_MODFUNC; /* unsupported function */
|
||||
}
|
||||
//
|
||||
return exc;
|
||||
}
|
||||
+88
-54
@@ -1,3 +1,25 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@@ -7,8 +29,16 @@
|
||||
#include "var.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
#define LF 10
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------ */
|
||||
#define CAR_DQUOTE '"'
|
||||
#define CAR_MARQUE_CLE ':'
|
||||
#define CAR_DEBUT_OBJET '{'
|
||||
@@ -25,23 +55,27 @@
|
||||
#define STR_FIN_TABLEAU "]"
|
||||
#define STR_SUIVANT ","
|
||||
|
||||
#define DEBUT_FICHIER 0
|
||||
#define VALEUR_CHAINE 1
|
||||
#define VALEUR_NOMBRE 2
|
||||
#define VALEUR_CLE 3
|
||||
#define DEBUT_OBJET 4
|
||||
#define FIN_OBJET 5
|
||||
#define DEBUT_TABLEAU 6
|
||||
#define FIN_TABLEAU 7
|
||||
#define SUIVANT 8
|
||||
#define FIN_FICHIER 9
|
||||
enum {
|
||||
DEBUT_FICHIER = 0,
|
||||
VALEUR_CHAINE = 1,
|
||||
VALEUR_NOMBRE = 2,
|
||||
VALEUR_CLE = 3,
|
||||
DEBUT_OBJET = 4,
|
||||
FIN_OBJET = 5,
|
||||
DEBUT_TABLEAU = 6,
|
||||
FIN_TABLEAU = 7,
|
||||
SUIVANT = 8,
|
||||
FIN_FICHIER = 9,
|
||||
|
||||
#define ENCODE_OK 1
|
||||
#define ENCODE_ERREUR 0
|
||||
ENCODE_OK = 1,
|
||||
ENCODE_ERREUR = 0,
|
||||
|
||||
LF = 10
|
||||
};
|
||||
|
||||
/* =================================================================================== */
|
||||
|
||||
/* --------- JSON C --------- */
|
||||
/* --------- PRIVATE --------- */
|
||||
static void ConcatValue(env * e, modContextJson * ctx, char c)
|
||||
{
|
||||
char car[2];
|
||||
@@ -611,7 +645,7 @@ static int GetNextTreeFetch(env * e, treefetch * tree)
|
||||
*/
|
||||
|
||||
/* =================== PUBLIC ========================== */
|
||||
int jsonInit(env * e, modContextJson * ctx)
|
||||
WAPIDECL int jsonInit(env * e, modContextJson * ctx)
|
||||
{
|
||||
int cr = OK;
|
||||
//cr += dynInit(e, &ctx->mKeyList, DYN_LGMIN);
|
||||
@@ -636,7 +670,7 @@ int jsonInit(env * e, modContextJson * ctx)
|
||||
return (cr == OK ? OK : EXMODJSON_MEM);
|
||||
}
|
||||
|
||||
int jsonEnd(env * e, modContextJson * ctx)
|
||||
WAPIDECL int jsonEnd(env * e, modContextJson * ctx)
|
||||
{
|
||||
//dynFree(e, &ctx->mKeyList);
|
||||
//dynFree(e, &ctx->mCurrentKey);
|
||||
@@ -648,76 +682,76 @@ int jsonEnd(env * e, modContextJson * ctx)
|
||||
return OK;
|
||||
}
|
||||
|
||||
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
|
||||
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * json, var * cle, var * valeur)
|
||||
{
|
||||
return Decode(e, ctx, param1->mPtr, param2, param3);
|
||||
return Decode(e, ctx, json->mPtr, cle, valeur);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -23,16 +23,20 @@
|
||||
#ifndef LANGAGE_H
|
||||
#define LANGAGE_H
|
||||
|
||||
#define VERSION 1 // version "max" gere du pcode => version du "langage"
|
||||
enum {
|
||||
VERSION = 1 // version "max" gere du pcode => version du "langage"
|
||||
};
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define W_LITTLE_ENDIAN 1
|
||||
#define W_BIG_ENDIAN 0
|
||||
#define W_DEFAULT_ENDIAN 2 // celle de la plateforme d'execution
|
||||
enum {
|
||||
W_LITTLE_ENDIAN = 1,
|
||||
W_BIG_ENDIAN = 0,
|
||||
W_DEFAULT_ENDIAN = 2 // celle de la plateforme d'execution
|
||||
};
|
||||
|
||||
typedef unsigned char octet;
|
||||
typedef octet * pointeur; /* et pas "void *" ... */
|
||||
@@ -44,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
|
||||
@@ -65,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) */
|
||||
|
||||
@@ -73,25 +73,28 @@ typedef ent64s number; /* 8 octets signes, virgule fixe */
|
||||
|
||||
/* les variables ne sont pas typees : elles peuvent changer de type au fur et a mesure des affectations */
|
||||
/* type 0 indique que l'emplacement n'a pas ete utilise encore : place disponible */
|
||||
#define VAR_NULL 1 /* variable declaree mais pas encore affectee d'une valeur */
|
||||
#define VAR_NUMBER 2 /* et @number */
|
||||
#define VAR_SUBROUTINE 3
|
||||
#define VAR_PARAM 4 /* adresse de la "vraie" variable, 1 seul niveau d'indirection, travail toujours sur la var "pointee" */
|
||||
#define VAR_DYNAMIC 5 /* et @string */
|
||||
#define VAR_HASHTABLE 6
|
||||
#define VAR_OBJECT 7 /* idem hashtable mais en objet : seule diff. element "_class" cree dans la table (interne) */
|
||||
#define VAR_BUFFER 8 /* usage interne : pile calcul + pile appel sub (autre ? buffer circulaire ptr read/write) */
|
||||
#define VAR_NB 8
|
||||
#define VAR_EMPTY 0 /* retour @empty */
|
||||
enum {
|
||||
VAR_NULL = 1, /* variable declaree mais pas encore affectee d'une valeur */
|
||||
VAR_NUMBER = 2, /* et @number */
|
||||
VAR_SUBROUTINE = 3,
|
||||
VAR_PARAM = 4, /* adresse de la "vraie" variable, 1 seul niveau d'indirection, travail toujours sur la var "pointee" */
|
||||
VAR_DYNAMIC = 5, /* et @string */
|
||||
VAR_HASHTABLE = 6,
|
||||
VAR_OBJECT = 7, /* idem hashtable mais en objet : seule diff. element "_class" cree dans la table (interne) */
|
||||
VAR_BUFFER = 8, /* usage interne : pile calcul + pile appel sub (autre ? buffer circulaire ptr read/write) */
|
||||
VAR_NB = 8,
|
||||
VAR_EMPTY = 0, /* retour @empty fonction type(expr) */
|
||||
|
||||
#define VAR_UNDECLARED -1
|
||||
VAR_UNDECLARED = 0, /* cas de retour si pas de var dans "typeof var1.var2.var3" */
|
||||
|
||||
#define CP_WIN1252 1252
|
||||
#define CP_8859_1 28591
|
||||
#define CP_8859_15 28605
|
||||
#define CP_UTF8 65001
|
||||
WCP_ASCII = 0, /* pour valeur par defaut */
|
||||
WCP_WIN1252 = 1252,
|
||||
WCP_8859_1 = 28591,
|
||||
WCP_8859_15 = 28605,
|
||||
WCP_UTF8 = 65001,
|
||||
|
||||
#define CP_DEFAULT CP_WIN1252 // UTF8 ??
|
||||
WCP_DEFAULT = WCP_ASCII // WIN1252 ? UTF8 ?
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
//union {
|
||||
@@ -127,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 */
|
||||
|
||||
@@ -146,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) */
|
||||
@@ -163,8 +166,6 @@ typedef struct {
|
||||
v->ptr v->ptr v->misc
|
||||
*/
|
||||
|
||||
#define BUF_LGMINBLOC 16384 /* multiple de 32 sinon pile d'elements 8 et 16 octets KO, lgmax message = lg buffer / 32 (512 octets ici) */
|
||||
|
||||
typedef struct {
|
||||
/* buffer servant de stack pour number et string */
|
||||
number num; /* nombre si str == NULL */
|
||||
@@ -187,66 +188,80 @@ typedef struct {
|
||||
/* vrai buffer read = position a lire dans les donnees (a ajouter a ptr) ou prochaine position a ecrire (pile calcul et appel) */
|
||||
/* vrai buffer write = position a ecrire dans les donnees (a ajouter a ptr) ; si READ=WRITE : vide ! ou utilise en interne si pile */
|
||||
|
||||
#define OID_MAX 9999999999999999ll /* pour que l'OID reste sur 16 chiffres : 16 neufs ici */
|
||||
#define OID_MAX 999999999999999ll /* pour que l'OID reste sur 16 chiffres : 15 neufs ici, pour qu'un oid commence toujours par 0 ! */
|
||||
#define OID_MIN 100ll /* demarrage a 100 pour eviter les nombres trop petits */
|
||||
|
||||
#define CLASS_BASE "Base" /* classe mere de toutes les classes */
|
||||
|
||||
#define MAX_PARAM 8 /* nb maxi de parametres d'une sub/methode */
|
||||
enum {
|
||||
BUF_LGMINBLOC = 16384, /* multiple de 32 sinon pile d'elements 8 et 16 octets KO, lgmax message = lg buffer / 32 (512 octets ici) */
|
||||
MAX_PARAM = 8, /* nb maxi de parametres d'une sub/methode */
|
||||
|
||||
#define HASH_READ 1
|
||||
#define HASH_DELETE 2
|
||||
#define HASH_WRITE 3
|
||||
HASH_READ = 1,
|
||||
HASH_DELETE = 2,
|
||||
HASH_WRITE = 3,
|
||||
|
||||
#define NOK -1 /* quand pas une exception */
|
||||
NOK = -1 /* quand pas une exception */
|
||||
};
|
||||
//
|
||||
// 000 a 999 : erreur systeme
|
||||
// 1000 a 9999 : reserve aux modules systeme
|
||||
// 1000 a 1099 : module "db"
|
||||
//
|
||||
#define OK 0
|
||||
#define EX_DIV0 1 /* exceptions */
|
||||
#define EX_MEM 2 /* memalloc ko */
|
||||
#define EX_BUFOVF 3 /* depassement de capacite du buffer */
|
||||
#define EX_IO 4 /* erreur d'entree/sortie (leture fichier...) */
|
||||
#define EX_END 5 /* adresse du code hors prog/sub */
|
||||
#define EX_LGNOM 6 /* lg nom variable incorrecte (de 1 a 24 inclus) */
|
||||
#define EX_TYPVAR 7 /* type variable non attendu */
|
||||
#define EX_NULLOCAL 8 /* hashtable locale null et pas dans le code "global" */
|
||||
#define EX_NOVAR 9 /* nom de variable inconnu */
|
||||
#define EX_MODOPEN 10 /* erreur ouverture module (dlopen) */
|
||||
#define EX_MODDSYM 11 /* fonction execModule non trouvee dans le module (dsym) */
|
||||
#define EX_NOSTACK 12 /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
|
||||
#define EX_NAVAR 13 /* la variable n'est pas du bon type / not available */
|
||||
#define EX_NOADVAR 14 /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
|
||||
#define EX_NAVERS 15 /* version de pcode non prise en charge par le "compilateur" */
|
||||
#define EX_MODNAME 16 /* le nom d'appel du module est incorrect */
|
||||
#define EX_DYNERR 17 /* erreur dans la manipulation des chaines */
|
||||
#define EX_MODFUNC 18 /* le code function du module est inconnu */
|
||||
#define EX_MODPARAM 19 /* le parametre donne au module est incorrect */
|
||||
#define EX_MODETAT 20 /* l'etat interne du module est incorrect */
|
||||
#define EX_MODERR 21 /* erreur specifique au module */
|
||||
#define EX_NOTNUM 22 /* erreur de conversion de chaine en number */
|
||||
#define EX_NOCLASS 23 /* la classe n'a pas ete trouvee dans la hash globale */
|
||||
#define EX_CMDLINE_ARG 24 /* erreur dans les parametres de la ligne de commande */
|
||||
#define EX_PCODE 25 /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
|
||||
#define EX_NOENVVAR 26 /* WBIN et/ou WSRC non defini en var d'environnement ou non passe en parametre de la ligne de commande */
|
||||
#define EX_EXCEPTNUM 27 /* code except ne tient pas sur 8 bits : ko pour retour shell */
|
||||
#define EX_BINVAR_KO 28 /* variable _bin de g non trouvee */
|
||||
#define EX_ENVVAR_KO 29 /* variable _env de g non trouvee */
|
||||
#define EX_BINADDRVAR_KO 30 /* variable _binaddr de g non trouvee */
|
||||
#define EX_CREATEHASH 31 /* erreur de creation de hashtable (memoire) */
|
||||
#define EX_FIELD_KO 32 /* erreur lors de dynField (memoire ou param incorrect) */
|
||||
#define EX_SUBSTR_KO 33 /* erreur lors de dynSubstr (memoire ou param incorrect) */
|
||||
#define EX_SEP_INCORRECT 34 /* separateurs incorrects dans setsep (0 interdit) */
|
||||
#define EX_FORMAT_KO 35 /* erreur de parametre (type format ou longueur incorrects) */
|
||||
#define EX_INSERT_KO 36 /* erreur de parametre ou memoire dans insert() */
|
||||
#define EX_REMOVE_KO 37 /* erreur de parametre ou memoire dans remove() */
|
||||
#define EXNB 37 /* MEMO !!!! */
|
||||
enum {
|
||||
OK = 0,
|
||||
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 (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 */
|
||||
EX_NULLOCAL = 8, /* hashtable locale null et pas dans le code "global" */
|
||||
EX_NOVAR = 9, /* nom de variable inconnu */
|
||||
EX_MODOPEN = 10, /* erreur ouverture module (dlopen) */
|
||||
EX_MODDSYM = 11, /* fonction execModule non trouvee dans le module (dsym) */
|
||||
EX_NOSTACK = 12, /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
|
||||
EX_NAVAR = 13, /* la variable n'est pas du bon type / not available */
|
||||
EX_NOADVAR = 14, /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
|
||||
EX_NAVERS = 15, /* version de pcode non prise en charge par le "compilateur" */
|
||||
EX_MODNAME = 16, /* le nom d'appel du module est incorrect */
|
||||
EX_DYNERR = 17, /* erreur dans la manipulation des chaines */
|
||||
EX_MODFUNC = 18, /* le code function du module est inconnu */
|
||||
EX_MODPARAM = 19, /* le parametre donne au module est incorrect */
|
||||
EX_MODETAT = 20, /* l'etat interne du module est incorrect */
|
||||
EX_MODERR = 21, /* erreur specifique au module */
|
||||
EX_NOTNUM = 22, /* erreur de conversion de chaine en number */
|
||||
EX_NOCLASS = 23, /* la classe n'a pas ete trouvee dans la hash globale */
|
||||
EX_CMDLINE_ARG = 24, /* erreur dans les parametres de la ligne de commande */
|
||||
EX_PCODE = 25, /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
|
||||
EX_NOENVVAR = 26, /* WBIN et/ou WSRC non defini en var d'environnement ou non passe en parametre de la ligne de commande */
|
||||
EX_EXCEPTNUM = 27, /* code except ne tient pas sur 8 bits : ko pour retour shell */
|
||||
EX_BINVAR_KO = 28, /* variable _bin de g non trouvee */
|
||||
EX_ENVVAR_KO = 29, /* variable _env de g non trouvee */
|
||||
EX_BINADDRVAR_KO = 30, /* variable _binaddr de g non trouvee */
|
||||
EX_CREATEHASH = 31, /* erreur de creation de hashtable (memoire) */
|
||||
EX_FIELD_KO = 32, /* erreur lors de dynField (memoire ou param incorrect) */
|
||||
EX_SUBSTR_KO = 33, /* erreur lors de dynSubstr (memoire ou param incorrect) */
|
||||
EX_SEP_INCORRECT = 34, /* separateurs incorrects dans setsep (0 interdit) */
|
||||
EX_FORMAT_KO = 35, /* erreur de parametre (type format ou longueur incorrects) */
|
||||
EX_INSERT_KO = 36, /* erreur de parametre ou memoire dans insert() */
|
||||
EX_REMOVE_KO = 37, /* erreur de parametre ou memoire dans remove() */
|
||||
EX_CHILD_FORK = 38, /* erreur de fork sur nouveau process */
|
||||
EX_CHILD_EXEC = 39, /* erreur execution nouveau process */
|
||||
EX_ZERO_FOR_INCR = 40, /* erreur increment a zero dans une boucle foreach numerique */
|
||||
EX_SORTEDSEARCH_KO = 41, /* erreur de parametre (type de tri incorrect) */
|
||||
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 */
|
||||
@@ -257,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 tblptr; /* 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 */
|
||||
@@ -267,6 +280,10 @@ typedef struct {
|
||||
var v; /* variable servant en interne */
|
||||
var * ad_var; /* permet de recuperer l'adresse d'une var entre 2 instructions */
|
||||
var * ad_var_hash; /* dans les enchainements PVAR/PVAH-PVAI, donne l'adresse de la hash possédant la "derniere" variable */
|
||||
var * ad_var_obj; /* dans une affectation let ou do sub, donne l'objet concerne si objet, pour lire les membres (hors sub) -> pour creer this */
|
||||
var * ad_var_class; /* donne l'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 ! */
|
||||
@@ -283,6 +300,8 @@ typedef struct {
|
||||
var debugreglelex;
|
||||
var debugcmd;
|
||||
var debugvalex;
|
||||
var printf;
|
||||
void * debugCtxShm; /* pour le debug des process phantom */
|
||||
/* */
|
||||
octet bin_comp; /* indique si les binaires lus sont compresses (1) et si oui, avec une cle (2), 0 RAS */
|
||||
octet demon; /* 1 si prog lance en demon, 0 sinon (lu par @demon) */
|
||||
@@ -297,6 +316,9 @@ typedef struct {
|
||||
char sep_field, sep_subfield; /* pour dynamic */
|
||||
/* */
|
||||
int endianess; /* pour detection automatique de l'endianess de la plateforme d'execution */
|
||||
int use_signal; /* 1 si w gere et traite les signaux, 0 sinon (mode plugin : signaux geres par programme maitre) */
|
||||
/* */
|
||||
int level; /* niveau d'imvrication des appels do/call ; prog principal = level 1 */
|
||||
/* */
|
||||
int bin_indice; /* position dans _bin du binaire en cours d'exec ( _bin<2, bin_indice> ) */
|
||||
/* */
|
||||
@@ -305,42 +327,79 @@ 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];
|
||||
/* */
|
||||
char var_car[VAR_NB + 1]; /* lettre caracteristique de chaque type (printdebug) */
|
||||
} env;
|
||||
|
||||
#define CMP_EQ 1
|
||||
#define CMP_NE 2
|
||||
#define CMP_LT 3
|
||||
#define CMP_GT 4
|
||||
#define CMP_LE 5
|
||||
#define CMP_GE 6
|
||||
enum {
|
||||
CMP_EQ = 1,
|
||||
CMP_NE = 2,
|
||||
CMP_LT = 3,
|
||||
CMP_GT = 4,
|
||||
CMP_LE = 5,
|
||||
CMP_GE = 6,
|
||||
CMP_AND = 7,
|
||||
CMP_OR = 8,
|
||||
CMP_NOT = 9,
|
||||
CMP_FOR = 10
|
||||
};
|
||||
|
||||
#define CMP_AND 7
|
||||
#define CMP_OR 8
|
||||
#define CMP_NOT 9
|
||||
enum {
|
||||
FORMAT_TRIM = 1,
|
||||
FORMAT_LEFT = 2,
|
||||
FORMAT_RIGHT = 3,
|
||||
FORMAT_CENTER = 4,
|
||||
FORMAT_SURROUND = 5
|
||||
};
|
||||
|
||||
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@forcount,@kill,@fork,@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,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"
|
||||
enum {
|
||||
SORTEDSEARCH_NONE = 0,
|
||||
SORTEDSEARCH_ASC = 1, // = DYN_SORT_ASC
|
||||
SORTEDSEARCH_DESC = 2 // = DYN_SORT_DESC
|
||||
};
|
||||
|
||||
#define GUV_CLASS "_class"
|
||||
#define GUV_BINADDR "_binaddr"
|
||||
#define GUV_LOCAL "_local"
|
||||
#define GUV_ENV "_env"
|
||||
#define GUV_ARG "_arg"
|
||||
#define GUV_WARGV "_wargv"
|
||||
#define GUV_ARGBACK "_argback"
|
||||
#define GUV_SRCDBG "_srcdbg"
|
||||
#define GUV_PROG "_prog"
|
||||
#define GUV_STACK "_stack"
|
||||
#define GUV_BIN "_bin"
|
||||
#define GUV_WDIR "_wdir"
|
||||
|
||||
#define GOV_THIS "this"
|
||||
#define GOV_PARENT "parent"
|
||||
|
||||
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@level,@kill,@oid,@prog,@pid,@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,16,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"
|
||||
|
||||
|
||||
@@ -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, ®les, 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, ®les, "lexlex"); // <regles> = regles lex compiles
|
||||
if(cr == DYN_OK)
|
||||
{
|
||||
init_reg_lex(e, ®les, &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, ®les, &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, ®les);
|
||||
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 = ""
|
||||
|
||||
@@ -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
|
||||
@@ -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
-4
@@ -1,6 +1,164 @@
|
||||
|
||||
//static char file_debuglex[] = "";
|
||||
static char file_debuglex[] = "blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,reste,8\n1,-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,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,free,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\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,66;1,1,72;1,1,65;1,1,65\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";
|
||||
@@ -1,3 +1,25 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "langage.h"
|
||||
@@ -7,8 +29,10 @@
|
||||
tester avec alloc (size 20) !! TODO
|
||||
*/
|
||||
|
||||
#define MAX_ENTRY 3838 // 4096 - 258
|
||||
#define SIZE_ENTRY (124 + sizeof(int)) // TODO : voir la meilleure taille 91 sur fichier binaire de 130 Ko... !!! tester avec 20...
|
||||
enum {
|
||||
MAX_ENTRY = 3838, // 4096 - 258
|
||||
SIZE_ENTRY = (124 + sizeof(int)) // TODO : voir la meilleure taille 91 sur fichier binaire de 130 Ko... !!! tester avec 20...
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
octet Dict[MAX_ENTRY * SIZE_ENTRY]; // dictionnaire en cours
|
||||
@@ -20,11 +44,12 @@ typedef struct {
|
||||
long prec; // dernier code trouve dans le dict
|
||||
long bits; // nb de bits en cours (codage/decodage)
|
||||
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal)
|
||||
int inverse; // "inverse" le decodage des bits LZW (cas des fichiers GIF)
|
||||
} modContextLzw;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void initLzw(env * e, modContextLzw * cl);
|
||||
void freeLzw(env * e, modContextLzw * cl);
|
||||
long setLzw(env * e, var * clair, modContextLzw * cl, int type);
|
||||
long getLzw(env * e, var * comp, modContextLzw * cl, int type);
|
||||
WAPIDECL void initLzw(env * e, modContextLzw * cl);
|
||||
WAPIDECL void freeLzw(env * e, modContextLzw * cl);
|
||||
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type);
|
||||
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type);
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -27,157 +27,170 @@
|
||||
|
||||
#include "langage.h"
|
||||
#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;
|
||||
|
||||
/*var dict; // de type dynamic, dictionnaire en cours
|
||||
var code; // de type dynamic, contient le code/decode en cours
|
||||
var w; // de type dynamic, contient la chaine en cours d'analyse
|
||||
long prec; // dernier code trouve dans le dict
|
||||
long posDict;// position en cours du code dans dict + 256 (dernier)
|
||||
long bits; // nb de bits en cours (codage/decodage)
|
||||
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal) */
|
||||
} 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"
|
||||
|
||||
//long set(env * e, var * clair, modEtat * pe, int type);
|
||||
//long get(env * e, var * code, modEtat * pe, int type);
|
||||
//long setV2(env * e, var * clair, modEtat * pe, int type);
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
|
||||
modEtat * p_etat;
|
||||
long exc = OK;
|
||||
// init/end/vers/error sont obligatoires pour tout module
|
||||
// - - - - - - - - - - - - - - - - - - - -
|
||||
if(param == NULL || etat == NULL)
|
||||
/* 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(param->type == VAR_PARAM)
|
||||
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
|
||||
//
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
/* 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);
|
||||
//dynInit(e, &p_etat->dict, 4096);
|
||||
//dynInit(e, &p_etat->code, 4096);
|
||||
//dynInit(e, &p_etat->w, 256);
|
||||
// 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(strncmp(e->fn, "end", 3) == 0)
|
||||
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);
|
||||
//dynFree(e, &p_etat->dict);
|
||||
//dynFree(e, &p_etat->code);
|
||||
//dynFree(e, &p_etat->w);
|
||||
//*** FIN du code specifique ici
|
||||
/* ============ here ============ */
|
||||
// liberation du module avant arret process
|
||||
memfree(e, p_etat);
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "vers", 4) == 0)
|
||||
else if(p_etat == NULL)
|
||||
{
|
||||
// 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
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
exc = EX_MODETAT;
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
var * paramVersion = getParam(e, "version", 7);
|
||||
if(paramVersion == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
if(param->type == VAR_NUMBER)
|
||||
param->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(strncmp(e->fn, "set", 3) == 0)
|
||||
else if(modFnIs(e, "set", 3))
|
||||
{
|
||||
/* compression du clair de param, en une fois */
|
||||
/* sinon utiliser : setinit, setnext, setend */
|
||||
/*exc = setError(p_etat, EXMOD_xxx);*/
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
/* get param in the right order */
|
||||
var * paramPlaintextThenCompressed = getParam(e, "plaintextThenCompressed", 23);
|
||||
if(paramPlaintextThenCompressed == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else if(paramPlaintextThenCompressed->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
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))
|
||||
{
|
||||
/* 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(paramCompressedThenPlaintext->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
if(param->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
exc = setError(p_etat, setLzw(e, param, &p_etat->cl, 0)); /* 0 : en une fois */
|
||||
p_etat->cl.inverse = FALSE;
|
||||
if(paramReverse != NULL)
|
||||
{
|
||||
if(paramReverse->type == VAR_DYNAMIC || paramReverse->type == VAR_NUMBER)
|
||||
{
|
||||
number inv;
|
||||
if(var_conv_num(e, paramReverse, &inv))
|
||||
p_etat->cl.inverse = (inv != 0 ? TRUE : FALSE);
|
||||
}
|
||||
}
|
||||
exc = setError(p_etat, getLzw(e, paramCompressedThenPlaintext, &p_etat->cl, 0)); /* decompression compatible PDF (et GIF si reverse = TRUE), 0 : en une fois */
|
||||
}
|
||||
}
|
||||
/* ============================================================================================= */
|
||||
else if(strncmp(e->fn, "get", 3) == 0)
|
||||
{
|
||||
/* decompression du code de param, en une fois */
|
||||
/* sinon utiliser getinit, getnext, getend */
|
||||
/*exc = setError(p_etat, EXMOD_xxx);*/
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else
|
||||
{
|
||||
if(param->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
exc = setError(p_etat, getLzw(e, param, &p_etat->cl, 0)); /* 0 : en une fois */
|
||||
}
|
||||
}
|
||||
/* ============================================================================================= */
|
||||
else if(strncmp(e->fn, "xxx", 3) == 0)
|
||||
{
|
||||
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
|
||||
exc = setError(p_etat, EXMOD_xxx);
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else
|
||||
{
|
||||
exc = EX_MODFUNC; // fonction non prise en charge
|
||||
exc = EX_MODFUNC; /* unsupported function */
|
||||
}
|
||||
//
|
||||
return exc;
|
||||
}
|
||||
/* **************************************************************************************************** */
|
||||
@@ -1,22 +1,41 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lzw.h"
|
||||
|
||||
void initLzw(env * e, modContextLzw * cl)
|
||||
{
|
||||
cl->allocEntry = 0;
|
||||
dynInit(e, &cl->code, 4096);
|
||||
dynInit(e, &cl->w, 256);
|
||||
}
|
||||
|
||||
void freeLzw(env * e, modContextLzw * cl)
|
||||
{
|
||||
dynFree(e, &cl->code);
|
||||
dynFree(e, &cl->w);
|
||||
}
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
/* ***** PRIVATE *************** */
|
||||
static void InitDict(env * e, modContextLzw * cl)
|
||||
{
|
||||
cl->posDict = 0; // prochaine entree
|
||||
@@ -124,9 +143,21 @@ static void ecrireCode(env * e, modContextLzw * cl, long num)
|
||||
cl->code.mInternal = b; /* nb bits libres restant */
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
/* ***** PUBLIC *************** */
|
||||
WAPIDECL void initLzw(env * e, modContextLzw * cl)
|
||||
{
|
||||
cl->allocEntry = 0;
|
||||
dynInit(e, &cl->code, 4096);
|
||||
dynInit(e, &cl->w, 256);
|
||||
}
|
||||
|
||||
long setLzw(env * e, var * clair, modContextLzw * cl, int type)
|
||||
WAPIDECL void freeLzw(env * e, modContextLzw * cl)
|
||||
{
|
||||
dynFree(e, &cl->code);
|
||||
dynFree(e, &cl->w);
|
||||
}
|
||||
|
||||
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type)
|
||||
{
|
||||
/* codage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
|
||||
if(type == 1 || type == 0)
|
||||
@@ -198,10 +229,10 @@ long setLzw(env * e, var * clair, modContextLzw * cl, int type)
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
long getLzw(env * e, var * comp, modContextLzw * cl, int type)
|
||||
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type)
|
||||
{
|
||||
long v; /* code en cours de decodage */
|
||||
long masque[8] = {0, 1, 3, 7, 15, 31, 63, 127};
|
||||
long masque[13] = {0, 1, 3, 7, 15, 31, 63, 127, 0, 511, 1023, 2047, 4095}; // les 8 premiers servent au mode normal, les 4 derniers au mode "inverse"
|
||||
/* decodage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
|
||||
if(type == 1 || type == 0)
|
||||
{
|
||||
@@ -225,16 +256,33 @@ long getLzw(env * e, var * comp, modContextLzw * cl, int type)
|
||||
/* lire les bits pour trouver le prochain code */
|
||||
c = *pcomp++;
|
||||
/* */
|
||||
cl->reste = (cl->reste << 8) | c;
|
||||
cl->code.mInternal += 8;
|
||||
if(cl->code.mInternal < cl->bits)
|
||||
continue;
|
||||
cl->code.mInternal -= cl->bits; /* maxi 7 bits restants */
|
||||
if(cl->code.mInternal == 0)
|
||||
v = cl->reste;
|
||||
if(cl->inverse) // test, sinon param "inverse"
|
||||
{
|
||||
// cas LZW du giff (different de LZW natif/PDF !)
|
||||
if(cl->code.mInternal == 0)
|
||||
cl->reste |= c;
|
||||
else
|
||||
cl->reste |= (c << cl->code.mInternal);
|
||||
cl->code.mInternal += 8;
|
||||
if(cl->code.mInternal < cl->bits)
|
||||
continue;
|
||||
v = (cl->reste & masque[cl->bits]);
|
||||
cl->reste >>= cl->bits;
|
||||
cl->code.mInternal -= cl->bits;
|
||||
}
|
||||
else
|
||||
v = cl->reste >> cl->code.mInternal;
|
||||
cl->reste &= masque[cl->code.mInternal];
|
||||
{
|
||||
cl->reste = (cl->reste << 8) | c;
|
||||
cl->code.mInternal += 8;
|
||||
if(cl->code.mInternal < cl->bits)
|
||||
continue;
|
||||
cl->code.mInternal -= cl->bits; /* maxi 7 bits restants */
|
||||
if(cl->code.mInternal == 0)
|
||||
v = cl->reste;
|
||||
else
|
||||
v = cl->reste >> cl->code.mInternal;
|
||||
cl->reste &= masque[cl->code.mInternal];
|
||||
}
|
||||
/* */
|
||||
if(v == 256)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,12 @@ static int setError(modEtat * p, int err)
|
||||
return EX_MODERR;
|
||||
}
|
||||
|
||||
#ifndef UNIX
|
||||
#define WLIBDECL __declspec(dllexport)
|
||||
#else
|
||||
#define WLIBDECL
|
||||
#endif
|
||||
|
||||
#ifndef UNIX
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,27 +1,50 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include "lzw.h"
|
||||
|
||||
/* ******* constantes ********** */
|
||||
#define PDFFMT_A4P 1 /* A4 portrait */
|
||||
#define PDFFMT_A4L 2 /* A4 paysage ("landscape") */
|
||||
#define PDFFMT_A3P 3 /* A3 portrait */
|
||||
#define PDFFMT_A3L 4 /* A3 paysage */
|
||||
|
||||
#define PDFFONT_COURIER 1
|
||||
#define PDFFONT_COURIER_BOLD 2
|
||||
#define PDFFONT_COURIER_BOLDOBLIQUE 3
|
||||
#define PDFFONT_COURIER_OBLIQUE 4
|
||||
#define PDFFONT_HELVETICA 5
|
||||
#define PDFFONT_HELVETICA_BOLD 6
|
||||
#define PDFFONT_HELVETICA_BOLDOBLIQUE 7
|
||||
#define PDFFONT_HELVETICA_OBLIQUE 8
|
||||
#define PDFFONT_TIMES_ROMAN 9
|
||||
#define PDFFONT_TIMES_BOLD 10
|
||||
#define PDFFONT_TIMES_ITALIC 11
|
||||
#define PDFFONT_TIMES_BOLDITALIC 12
|
||||
#define PDFFONT_SYMBOL 13
|
||||
#define PDFFONT_ZAPFDINGBATS 14
|
||||
#define PDFFONT_NB 14
|
||||
enum {
|
||||
PDFFMT_A4P = 1, /* A4 portrait */
|
||||
PDFFMT_A4L = 2, /* A4 paysage ("landscape") */
|
||||
PDFFMT_A3P = 3, /* A3 portrait */
|
||||
PDFFMT_A3L = 4, /* A3 paysage */
|
||||
|
||||
PDFFONT_COURIER = 1,
|
||||
PDFFONT_COURIER_BOLD = 2,
|
||||
PDFFONT_COURIER_BOLDOBLIQUE = 3,
|
||||
PDFFONT_COURIER_OBLIQUE = 4,
|
||||
PDFFONT_HELVETICA = 5,
|
||||
PDFFONT_HELVETICA_BOLD = 6,
|
||||
PDFFONT_HELVETICA_BOLDOBLIQUE = 7,
|
||||
PDFFONT_HELVETICA_OBLIQUE = 8,
|
||||
PDFFONT_TIMES_ROMAN = 9,
|
||||
PDFFONT_TIMES_BOLD = 10,
|
||||
PDFFONT_TIMES_ITALIC = 11,
|
||||
PDFFONT_TIMES_BOLDITALIC = 12,
|
||||
PDFFONT_SYMBOL = 13,
|
||||
PDFFONT_ZAPFDINGBATS = 14,
|
||||
PDFFONT_NB = 14
|
||||
};
|
||||
|
||||
/* ***** MACRO ****/
|
||||
#define RGB(r,g,b) (((((r&255)<<8)+(g&255))<<8)+(b&255))
|
||||
@@ -31,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 */
|
||||
@@ -45,18 +70,26 @@ 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 */
|
||||
|
||||
Dynamic mTmp1, mTmp2; /* temporaire pour le traitement */
|
||||
Dynamic mTmp1, mTmp2, mTmp3; /* temporaire pour le traitement */
|
||||
} modContextPdf;
|
||||
|
||||
void initPdf(env * e, modContextPdf * ctxPdf);
|
||||
void freePdf(env * e, modContextPdf * ctxPdf);
|
||||
int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts);
|
||||
int endPdf(env * e, modContextPdf * ctxPdf);
|
||||
int setPdfPage(env * e, modContextPdf * ctxPdf, int compression);
|
||||
int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt);
|
||||
int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille);
|
||||
int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img);
|
||||
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf);
|
||||
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf);
|
||||
WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts);
|
||||
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf);
|
||||
WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf);
|
||||
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression);
|
||||
WAPIDECL int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt);
|
||||
WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille);
|
||||
WAPIDECL int 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);
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -30,68 +30,70 @@
|
||||
#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"
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
modEtat * p_etat;
|
||||
long exc = OK;
|
||||
// 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))
|
||||
{
|
||||
@@ -99,118 +101,331 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
|
||||
{
|
||||
//*** 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->type != VAR_HASHTABLE)
|
||||
/* get param in the right order */
|
||||
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
|
||||
if(paramPdfParameterSet == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
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;
|
||||
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
|
||||
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fontes"), &fontes);
|
||||
if(titre && fontes)
|
||||
var * titre, * fontes, * nbPage, * 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)
|
||||
exc = setError(p_etat, ! newPdf(e, &p_etat->cp, titre, 1, PDFFMT_A4P, fontes));
|
||||
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) ? 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
|
||||
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
|
||||
exc = setError(p_etat, ! setPdfText(e, &p_etat->cp, 100, 900, 300, 300, 1, 10, 0, param2));
|
||||
var * x, * y, * w, * h; // cadre englobant
|
||||
var * fonte, * taille, * 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, paramString) ? OK : EXMOD_PDF_INTERNAL_ERR);
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
/* ---------------------------------------------------- */
|
||||
else if(modFnIs(e, "addCab128", 9))
|
||||
{
|
||||
/* 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(paramPdfParameterSet->type != VAR_HASHTABLE || paramString->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
// 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 = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
}
|
||||
/* ---------------------------------------------------- */
|
||||
else if(modFnIs(e, "addGraph", 8))
|
||||
{
|
||||
/* get param in the right order */
|
||||
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
|
||||
if(paramPdfParameterSet == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
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, 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) ? OK : EXMOD_PDF_INTERNAL_ERR);
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
}
|
||||
/* ---------------------------------------------------- */
|
||||
else if(modFnIs(e, "addImage", 8))
|
||||
{
|
||||
/* get param in the right order */
|
||||
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
|
||||
if(paramPdfParameterSet == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
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, 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) ? OK : EXMOD_PDF_INTERNAL_ERR);
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
}
|
||||
/* ---------------------------------------------------- */
|
||||
else if(modFnIs(e, "loadImage", 9))
|
||||
{
|
||||
/* 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(paramImage->type != VAR_DYNAMIC || paramFormat->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
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))
|
||||
{
|
||||
/* 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(paramPdfParameterSet->type != VAR_HASHTABLE || paramTextThenPdfContent->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
var * titre, * 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 || format->type == VAR_DYNAMIC))
|
||||
{
|
||||
number nformat;
|
||||
if( var_conv_num(e, format, &nformat) )
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
|
||||
}
|
||||
else
|
||||
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;
|
||||
}
|
||||
@@ -1,6 +1,38 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include "pdf.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
//
|
||||
// creation fichier PDF
|
||||
//
|
||||
@@ -133,10 +165,75 @@
|
||||
|
||||
#include "stdio.h"
|
||||
|
||||
#define PDF_CONV1 72000
|
||||
#define PDF_CONV2 2540
|
||||
enum {
|
||||
PDF_CONV1 = 72000,
|
||||
PDF_CONV2 = 2540
|
||||
};
|
||||
/* valeur en dixieme de mm * CONV11 / CONV2 = valeur en unites pdf x 100 (72 dpi = 72 points par pouce ; 1 pouce = 25.4) */
|
||||
|
||||
// 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)
|
||||
{
|
||||
@@ -169,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"
|
||||
@@ -221,8 +325,54 @@ static int fmtc(env * e, Dynamic * res, long coul)
|
||||
return cr;
|
||||
}
|
||||
|
||||
static void convertHexaRGBToBinLzw(env * e, modContextPdf * ctxPdf)
|
||||
{
|
||||
// ctxPdf->mTmp1 contient les donnees en entree, et ctxPdf->mTmp2 en sortie le lzw binaire
|
||||
// conversion de mTmp1 RGB hexa en binaire dans mTmp2
|
||||
dynSetLen(e, &ctxPdf->mTmp2, 0);
|
||||
long i, nb = ctxPdf->mTmp1.mLg / 6; // RRGGBB = 6 octets
|
||||
octet * p = ctxPdf->mTmp1.ptr;
|
||||
char res[4] = {0};
|
||||
for(i = 0; i < nb; i++, p += 6)
|
||||
{
|
||||
dynConvertCharHexaToChar(*p, *(p+1), res);
|
||||
dynConvertCharHexaToChar(*(p+2), *(p+3), res + 1);
|
||||
dynConvertCharHexaToChar(*(p+4), *(p+5), res + 2);
|
||||
dynConcatSz(e, &ctxPdf->mTmp2, res, 3);
|
||||
}
|
||||
// compression lzw de e->mTmp2
|
||||
setLzw(e, &ctxPdf->mTmp2, &ctxPdf->mCtxLzw, 0);
|
||||
}
|
||||
|
||||
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 ************************************************************************/
|
||||
void initPdf(env * e, modContextPdf * ctxPdf)
|
||||
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf)
|
||||
{
|
||||
ctxPdf->mLmarg = 100; /* dixieme de mm ( = 1 cm ici) */
|
||||
ctxPdf->mRmarg = 100;
|
||||
@@ -235,38 +385,63 @@ void initPdf(env * e, modContextPdf * ctxPdf)
|
||||
dynInit(e, &ctxPdf->mFont, 256);
|
||||
dynInit(e, &ctxPdf->mTmp1, 1024);
|
||||
dynInit(e, &ctxPdf->mTmp2, 1024);
|
||||
dynInit(e, &ctxPdf->mTmp3, 1024);
|
||||
dynInit(e, &ctxPdf->mPage, 4096);
|
||||
dynInit(e, &ctxPdf->mPdf, 8192);
|
||||
ctxPdf->mPdf.type = VAR_DYNAMIC;
|
||||
dynInit(e, &ctxPdf->mXref, 1024);
|
||||
dynInit(e, &ctxPdf->mImg, 2048);
|
||||
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);
|
||||
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
|
||||
}
|
||||
|
||||
void freePdf(env * e, modContextPdf * ctxPdf)
|
||||
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf)
|
||||
{
|
||||
freeLzw(e, &ctxPdf->mCtxLzw);
|
||||
/* */
|
||||
dynFree(e, &ctxPdf->mFont);
|
||||
dynFree(e, &ctxPdf->mTmp1);
|
||||
dynFree(e, &ctxPdf->mTmp2);
|
||||
dynFree(e, &ctxPdf->mTmp3);
|
||||
dynFree(e, &ctxPdf->mPage);
|
||||
dynFree(e, &ctxPdf->mPdf);
|
||||
dynFree(e, &ctxPdf->mXref);
|
||||
dynFree(e, &ctxPdf->mImg);
|
||||
dynFree(e, &ctxPdf->mInfoPage);
|
||||
dynFree(e, &ctxPdf->mEan128);
|
||||
}
|
||||
|
||||
int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts)
|
||||
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)
|
||||
@@ -306,9 +481,11 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
|
||||
/* */
|
||||
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
|
||||
@@ -319,22 +496,28 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
|
||||
dynConcatSz(e, &ctxPdf->mPdf, "2 0 obj << /Producer (WPDF) /Author (WPDF) /Title (", DYN_LGNONE);
|
||||
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1); /* titre "echape" */
|
||||
dynConcatSz(e, &ctxPdf->mPdf, ") /CreationDate (", DYN_LGNONE);
|
||||
dynConcatSz(e, &ctxPdf->mPdf, "20000101140000", DYN_LGNONE); // TODO date courante YMDhms dynOconv(e, ...)
|
||||
dynSetLen(e, &ctxPdf->mTmp1, 0); // empty => oconv will convert time of the day
|
||||
dynOconv(e, &ctxPdf->mTmp1, &ctxPdf->mTmp2, "DYMDhmsZ");
|
||||
dynConcatSz(e, &ctxPdf->mPdf, "D:", 2);
|
||||
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
|
||||
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);
|
||||
@@ -349,6 +532,9 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
|
||||
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++)
|
||||
{
|
||||
@@ -365,11 +551,12 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
|
||||
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 /ASCIIHexDecode /Length ", DYN_LGNONE); // TODO remplacer /ASCIIHexDecode par /LZW...
|
||||
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
|
||||
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mTmp1.mLg, FALSE, 0), DYN_LGNONE);
|
||||
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->mTmp1);
|
||||
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
|
||||
dynConcatSz(e, &ctxPdf->mPdf,"\r\nendstream\r\nendobj\r\n", DYN_LGNONE);
|
||||
}
|
||||
/* definition de chaque page */
|
||||
@@ -386,7 +573,7 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
|
||||
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);
|
||||
@@ -397,7 +584,7 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
|
||||
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);
|
||||
@@ -409,9 +596,24 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
|
||||
return cr;
|
||||
}
|
||||
|
||||
int endPdf(env * e, modContextPdf * ctxPdf)
|
||||
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);
|
||||
@@ -422,7 +624,7 @@ int endPdf(env * e, modContextPdf * ctxPdf)
|
||||
dynConcatSz(e, &ctxPdf->mPdf, "\r\n0000000000 65535 f\r\n", DYN_LGNONE);
|
||||
else
|
||||
{
|
||||
dynField(e, &ctxPdf->mXref, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
|
||||
dynField(e, &ctxPdf->mXref, &ctxPdf->mTmp1, i, 1, cFM, cVM, 1); // VM1 a cause des images (x et y dans xref<x,2>...)
|
||||
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
|
||||
dynConcatSz(e, &ctxPdf->mPdf, " 00000 n\r\n", DYN_LGNONE);
|
||||
}
|
||||
@@ -435,19 +637,52 @@ int endPdf(env * e, modContextPdf * ctxPdf)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Dynamic * getPdf(env * e, modContextPdf * ctxPdf)
|
||||
WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf)
|
||||
{
|
||||
return &ctxPdf->mPdf;
|
||||
}
|
||||
|
||||
int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
|
||||
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);
|
||||
@@ -460,10 +695,8 @@ 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);
|
||||
@@ -475,7 +708,7 @@ int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
|
||||
return cr;
|
||||
}
|
||||
|
||||
int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt)
|
||||
WAPIDECL int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt)
|
||||
{
|
||||
int cr = TRUE;
|
||||
/* x,y,w,h en mm, font de 1 a PDF_FONT_NB, couleur avec RGB(r,g,b) */
|
||||
@@ -495,7 +728,7 @@ int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h,
|
||||
return cr;
|
||||
}
|
||||
|
||||
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 setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille)
|
||||
{
|
||||
int cr = TRUE;
|
||||
/* x,y,w,h en mm, font de 1 a PDF_FONT_NB, coul_trait/coul_rempl avec RGB(r,g,b), epaisseur et pointille de 0 a 9 */
|
||||
@@ -549,7 +782,34 @@ int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long
|
||||
return cr;
|
||||
}
|
||||
|
||||
int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
|
||||
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;
|
||||
/* x,y en mm, image numero <img> */
|
||||
@@ -567,121 +827,322 @@ int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
|
||||
return cr;
|
||||
}
|
||||
|
||||
/* debug TODO ---------------------------------------- */
|
||||
//int pdfChargeImageRGB(env * e, Dynamic * pixel)
|
||||
WAPIDECL int pdfDeleteImage(env * e, modContextPdf * ctxPdf, long img)
|
||||
{
|
||||
// delete image number <img>, if 0 delete all
|
||||
if(img > 0)
|
||||
dynDel(e, &ctxPdf->mImg, img, DYN_NONE, cFM, DYN_NONE, 1);
|
||||
else
|
||||
dynSetLen(e, &ctxPdf->mImg, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//int pdfLoadImageRGB(env * e, Dynamic * pixel)
|
||||
//{
|
||||
// /* TODO png, jpeg,... en amont*/
|
||||
// return TRUE;
|
||||
//}
|
||||
//
|
||||
//int pdfChargeImageBmp(env * e, char * fichier)
|
||||
//{
|
||||
// long bpp, larg, haut, offset, par_ligne;
|
||||
// char * p; /* pour simplifier le code... */
|
||||
// long i, j, pos;
|
||||
// /* lecture fichier */
|
||||
// if(!ctxPdf->mTmp1.read(fichier))
|
||||
// return FALSE;
|
||||
// // controle du bitmap avant memorisation
|
||||
// p = ctxPdf->mTmp1.getPtr();
|
||||
// if(p[0] != 'B' && p[1] != 'M')
|
||||
// return FALSE; /* pas un fichier .bmp */
|
||||
// //
|
||||
// bpp = p[28];
|
||||
// if(bpp != 24 && bpp != 32)
|
||||
// return FALSE; /* uniquement les fichiers bmp encodes en 24bpp ou 32bpp */
|
||||
// bpp = bpp >> 3;
|
||||
// /* */
|
||||
// offset = (p[11]<<8) + p[10];
|
||||
// larg = (p[19]<<8) + p[18];
|
||||
// haut = (p[23]<<8) + p[22];
|
||||
// par_ligne = larg * bpp; /* nb octets par ligne */
|
||||
// if((par_ligne&3) != 0)
|
||||
// par_ligne += (4 - (par_ligne&3));
|
||||
// /* la bitmap en hexa fera une taille de larg*haut*3*2 */
|
||||
// if(!ctxPdf->mImg.ctrl(ctxPdf->mImg.getLen() + larg * haut * 6 + 13, TRUE)) /* 13: inclut largeur/hauteur et séparateurs FM VM */
|
||||
// return FALSE;
|
||||
// //
|
||||
// if(ctxPdf->mImg.getLen() != 0)
|
||||
// {
|
||||
// ctxPdf->mImg.concat(sFM);
|
||||
// }
|
||||
// ctxPdf->mImg.concat(larg, "%ld" sVM);
|
||||
// ctxPdf->mImg.concat(haut, "%ld" sVM);
|
||||
// // boucle sur chaque pixel
|
||||
// for(i = haut-1; i >= 0; i--)
|
||||
// for(j = 0; j < larg; j++)
|
||||
// {
|
||||
// pos = offset + j*bpp + i*par_ligne;
|
||||
// ctxPdf->mImg.concat( (((p[pos+2]<<8)+p[pos+1])<<8)+p[pos], "%6X");
|
||||
// }
|
||||
// return TRUE;
|
||||
//}
|
||||
//
|
||||
//int pdfList(env * e, char * titre, Dynamic & lignes, long format, long compression)
|
||||
//{
|
||||
// long nbPage, nbLig, nbLigPage, nbColPage;
|
||||
// long iPage, iLig, iPos;
|
||||
// long tmp;
|
||||
// // enchaine automatiquement les fonctions pour creer un pdf de type "listing" (log ou programme)
|
||||
// // police Courrier taille 9 en A4 =>
|
||||
// // paysage : 60 lignes 145 colonnes
|
||||
// // portrait : 87 lignes 99 colonnes
|
||||
// if(format == PDF_A4P)
|
||||
// {
|
||||
// // portrait
|
||||
// nbLigPage = 87;
|
||||
// nbColPage = 99;
|
||||
// }
|
||||
// else if(format == PDF_A4L)
|
||||
// {
|
||||
// // paysage (Landscape)
|
||||
// nbLigPage = 60;
|
||||
// nbColPage = 145;
|
||||
// }
|
||||
// else
|
||||
// return FALSE; // format non pris en charge
|
||||
// //
|
||||
// lignes.erase("\r");
|
||||
// nbLig = lignes.dcount(10); // \n
|
||||
// if(nbLig == 0)
|
||||
// nbPage = 1;
|
||||
// else
|
||||
// nbPage = (nbLig - 1) / nbLigPage + 1;
|
||||
// //
|
||||
// if(!ctxPdf->nouveau(titre, nbPage, format))
|
||||
// return FALSE; // erreur
|
||||
// //
|
||||
// iPos = 1;
|
||||
// for(iPage = 1; iPage <= nbPage; iPage++)
|
||||
// {
|
||||
// //if(logo_societe(mLarg * 10 / mRatio - 20, mHaut * 10 / mRatio - 20))
|
||||
// // ctxPdf->mPage.concat(mTmp1);
|
||||
// ctxPdf->mPage.concat("BT /F1 9 Tf ");
|
||||
// ctxPdf->mPage.concat(ctxPdf->mRatio * mLmarg / 100, "%ld.");
|
||||
// ctxPdf->mPage.concat(ctxPdf->mRatio * mLmarg % 100, "%ld ");
|
||||
// tmp = mHaut * 10 - (ctxPdf->mRatio * mHmarg);
|
||||
// ctxPdf->mPage.concat(tmp / 100, "%ld.");
|
||||
// ctxPdf->mPage.concat(tmp % 100, "%ld");
|
||||
// ctxPdf->mPage.concat(" Td 9 TL\r\n");
|
||||
// //
|
||||
// for(iLig = 1; iLig <= nbLigPage && iPos <= nbLig; iLig++)
|
||||
// {
|
||||
// lignes.field(10, iPos++, mTmp1); // 10 = \n
|
||||
// mTmp1.substr(0, nbColPage, mTmp2); // tronque au nb de colonnes max
|
||||
// ctxPdf->echap_txt(mTmp1, mTmp2.getPtr());
|
||||
// ctxPdf->mPage.concat("(");
|
||||
// ctxPdf->mPage.concat(mTmp1);
|
||||
// ctxPdf->mPage.concat(") '\r\n");
|
||||
// }
|
||||
// //
|
||||
// ctxPdf->mPage.concat("ET\r\n");
|
||||
// //
|
||||
// if(!ctxPdf->page(compression))
|
||||
// return FALSE; // erreur
|
||||
// }
|
||||
// //
|
||||
// return ctxPdf->termine();
|
||||
//}
|
||||
|
||||
/* ******************************************************** */
|
||||
WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
|
||||
{
|
||||
long bpp, larg, haut, offset, par_ligne;
|
||||
octet * p; /* pour simplifier le code... */
|
||||
long i, j, pos, ind;
|
||||
/* lecture fichier */
|
||||
if(!fichier)
|
||||
return FALSE;
|
||||
if(fichier->type != VAR_DYNAMIC)
|
||||
return FALSE;
|
||||
// controle du bitmap avant memorisation
|
||||
p = fichier->ptr;
|
||||
if(p[0] != 'B' && p[1] != 'M')
|
||||
return FALSE; /* pas un fichier .bmp */
|
||||
//
|
||||
bpp = p[28];
|
||||
if(bpp != 24 && bpp != 32)
|
||||
return FALSE; /* uniquement les fichiers bmp encodes en 24bpp ou 32bpp */
|
||||
bpp = bpp >> 3;
|
||||
/* */
|
||||
offset = (p[11] << 8) + p[10];
|
||||
larg = (p[19] << 8) + p[18];
|
||||
haut = (p[23] << 8) + p[22];
|
||||
par_ligne = larg * bpp; /* nb octets par ligne */
|
||||
if((par_ligne & 3) != 0)
|
||||
par_ligne += (4 - (par_ligne & 3));
|
||||
/* la bitmap en hexa fera une taille de larg*haut*3*2 */
|
||||
ind = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE) + 1;
|
||||
dynStoreNumber(e, &ctxPdf->mImg, ind, 1, larg, cFM, cVM);
|
||||
dynStoreNumber(e, &ctxPdf->mImg, ind, 2, haut, cFM, cVM);
|
||||
dynConcatSz(e, &ctxPdf->mImg, sVM, 1);
|
||||
// boucle sur chaque pixel
|
||||
for(i = haut-1; i >= 0; i--)
|
||||
for(j = 0; j < larg; j++)
|
||||
{
|
||||
pos = offset + j * bpp + i * par_ligne;
|
||||
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos + 2]), 2);
|
||||
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos + 1]), 2);
|
||||
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos]), 2);
|
||||
}
|
||||
//printf("Image:\n%s\nlarg:%ld haut:%ld bpp:%ld ind:%ld parligne:%ld lenfichier:%lld\n", ctxPdf->mImg.mPtr, larg, haut, bpp, ind, par_ligne, fichier->mLg);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WAPIDECL int 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)
|
||||
// police Courrier taille 9 en A4 =>
|
||||
// paysage : 60 lignes 145 colonnes
|
||||
// portrait : 87 lignes 99 colonnes
|
||||
long nbLigPage, nbColPage;
|
||||
if(format == PDFFMT_A4P)
|
||||
{
|
||||
// portrait
|
||||
nbLigPage = 87;
|
||||
nbColPage = 99;
|
||||
}
|
||||
else if(format == PDFFMT_A4L)
|
||||
{
|
||||
// paysage (Landscape)
|
||||
nbLigPage = 60;
|
||||
nbColPage = 145;
|
||||
}
|
||||
else
|
||||
return FALSE; // format non pris en charge
|
||||
//
|
||||
long nbPage, nbLig;
|
||||
dynErase(e, lignes, "\r");
|
||||
nbLig = dynDcount(e, lignes, 10, DYN_NONE, DYN_NONE); // \n
|
||||
if(nbLig == 0)
|
||||
nbPage = 1;
|
||||
else
|
||||
nbPage = (nbLig - 1) / nbLigPage + 1;
|
||||
//
|
||||
dynLet(e, &ctxPdf->mTmp3, "Courier", DYN_LGNONE);
|
||||
if( ! newPdf(e, ctxPdf, titre, nbPage, format, &ctxPdf->mTmp3))
|
||||
return FALSE;
|
||||
//
|
||||
long iPage, iLigPage, iLigTotal = 1;
|
||||
for(iPage = 1; iPage <= nbPage; iPage++)
|
||||
{
|
||||
dynConcatSz(e, &ctxPdf->mPage, "BT /F1 9 Tf ", 12); // Fonte 1 = Courier (/F1)
|
||||
fmt2(e, &ctxPdf->mPage, ctxPdf->mLmarg, ctxPdf->mHaut - ctxPdf->mHmarg);
|
||||
dynConcatSz(e, &ctxPdf->mPage, " Td 9 TL\r\n", DYN_LGNONE);
|
||||
//
|
||||
for(iLigPage = 1; iLigPage <= nbLigPage && iLigTotal <= nbLig; iLigPage++)
|
||||
{
|
||||
dynField(e, lignes, &ctxPdf->mTmp1, iLigTotal++, DYN_NONE, 10, DYN_NONE, 1);
|
||||
if(ctxPdf->mTmp1.mLg > nbColPage)
|
||||
dynSetLen(e, &ctxPdf->mTmp1, nbColPage);
|
||||
pdfEchap(e, &ctxPdf->mTmp2, &ctxPdf->mTmp1);
|
||||
dynConcatSz(e, &ctxPdf->mPage, "(", 1);
|
||||
dynConcatSz(e, &ctxPdf->mPage, ctxPdf->mTmp2.mPtr, ctxPdf->mTmp2.mLg);
|
||||
dynConcatSz(e, &ctxPdf->mPage, ") '\r\n", DYN_LGNONE);
|
||||
}
|
||||
dynConcatSz(e, &ctxPdf->mPage, "ET\r\n", DYN_LGNONE);
|
||||
//
|
||||
if( ! setPdfPage(e, ctxPdf, 1)) // avec compression
|
||||
return FALSE;
|
||||
}
|
||||
return endPdf(e, ctxPdf);
|
||||
}
|
||||
|
||||
/* ******************************************************** */
|
||||
+121
-93
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -27,9 +27,13 @@
|
||||
|
||||
#include "langage.h"
|
||||
#include "dynamic.h"
|
||||
#include "var.h"
|
||||
|
||||
#define RAND_STATE_COUNT 624
|
||||
#define RAND_PERIOD 397
|
||||
/* ============================================================================================= */
|
||||
enum {
|
||||
RAND_STATE_COUNT = 624,
|
||||
RAND_PERIOD = 397
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int error; // dernier code erreur specifique au module
|
||||
@@ -60,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);
|
||||
@@ -73,130 +77,154 @@ 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"
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
|
||||
modEtat * p_etat;
|
||||
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 */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
|
||||
if(modFnIs(e, "init", 4))
|
||||
{
|
||||
// alloc ptr sur zone memoire pour memoriser l'etat du module
|
||||
*etat = memalloc(e, sizeof(modEtat));
|
||||
if(*etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else
|
||||
{
|
||||
p_etat = (modEtat *)(*etat);
|
||||
p_etat->error = 0;
|
||||
//*** code specifique ici
|
||||
randomInit(p_etat, time(NULL));
|
||||
//
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "end", 3) == 0)
|
||||
{
|
||||
//*** code specifique ici
|
||||
//
|
||||
// liberation specifique au module avant arret process
|
||||
if(p_etat != NULL)
|
||||
memfree(e, p_etat);
|
||||
}
|
||||
else if(strncmp(e->fn, "vers", 4) == 0)
|
||||
{
|
||||
if(param1 == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
// renvoie la version du module/plugins
|
||||
if(param1->type == VAR_DYNAMIC)
|
||||
dynLet(e, param1, "1", 1); //*** version en alpha
|
||||
else if(param1->type == VAR_NUMBER)
|
||||
param1->num = NUM_UN; //*** version en numerique
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(param1 == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
if(param1->type == VAR_NUMBER)
|
||||
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
|
||||
// alloc ptr sur zone memoire pour memoriser l'etat du module
|
||||
*etat = memalloc(e, sizeof(modEtat));
|
||||
if(*etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else
|
||||
exc = EX_MODPARAM; // bad type of parameter
|
||||
{
|
||||
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))
|
||||
{
|
||||
if(p_etat != NULL)
|
||||
{
|
||||
//*** code specifique ici
|
||||
/* ============ here ============ */
|
||||
// liberation du module avant arret process
|
||||
memfree(e, p_etat);
|
||||
}
|
||||
}
|
||||
/* ============================================================================================= */
|
||||
else if(strncmp(e->fn, "setSeed", 7) == 0)
|
||||
else if(p_etat == NULL)
|
||||
{
|
||||
if(param1 == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else if(param1->type != VAR_NUMBER)
|
||||
exc = EX_MODETAT;
|
||||
}
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
var * paramVersion = getParam(e, "version", 7);
|
||||
if(paramVersion == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
randomInit(p_etat, (ent32)((param1->num / NUM_FACTEUR) & 0xFFFFFFFF));
|
||||
// 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(strncmp(e->fn, "get", 3) == 0)
|
||||
else if(modFnIs(e, "error", 5))
|
||||
{
|
||||
if(param1 == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else if(param1->type != VAR_NUMBER)
|
||||
/* 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
|
||||
{
|
||||
param1->num = (((ent64)(randomGenerate(p_etat))) * NUM_FACTEUR);
|
||||
// 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, "setSeed", 7))
|
||||
{
|
||||
/* get param in the right order */
|
||||
var * paramSeedValue = getParam(e, "seedValue", 9);
|
||||
if(paramSeedValue == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else if(paramSeedValue->type != VAR_NUMBER && paramSeedValue->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
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))
|
||||
{
|
||||
/* get param in the right order */
|
||||
var * paramNextRandomNumber = getParam(e, "nextRandomNumber", 16);
|
||||
if(paramNextRandomNumber == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
@@ -26,17 +26,56 @@
|
||||
|
||||
// TODO version windows
|
||||
#ifdef UNIX
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include "windows.h" // pour les fonctions FindFile...
|
||||
#include "windows.h" // pour les fonctions FindFile...
|
||||
#endif
|
||||
|
||||
#include "langage.h"
|
||||
#include "dynamic.h"
|
||||
#include "rep.h"
|
||||
|
||||
long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount)
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
/* ******** PRIVATE ********************* */
|
||||
static int GetInclude(env * e, Dynamic * line, Dynamic * includeFilename)
|
||||
{
|
||||
// check that the <line> is a include w statement. If not, return zero, else
|
||||
// return in <includeFilename> the name of the include file
|
||||
// separators are 9 and 32 (tab and space) and ";"" for the optional end of line comment
|
||||
char * p = line->mPtr, * q;
|
||||
while(*p && (*p == 9 || *p == 32)) p++;
|
||||
if(*p++ != 'i') return 0;
|
||||
if(*p++ != 'n') return 0;
|
||||
if(*p++ != 'c') return 0;
|
||||
if(*p++ != 'l') return 0;
|
||||
if(*p++ != 'u') return 0;
|
||||
if(*p++ != 'd') return 0;
|
||||
if(*p++ != 'e') return 0;
|
||||
if(*p != 9 && *p != 32) return 0;
|
||||
p++;
|
||||
while(*p && (*p == 9 || *p == 32)) p++;
|
||||
if(*p != '\'' && *p != '"') return 0;
|
||||
q = p + 1; // *p is the first char of include filename , including ' or ", and that chra must bi found at the end of the file
|
||||
while(*q && (*q != *p)) q++;
|
||||
if(*q != *p) return 0; // *q must be the same ' or " that begins filename
|
||||
long lg = q - p - 1;
|
||||
if(lg < 1) return 0;
|
||||
dynLet(e, includeFilename, p + 1, lg);
|
||||
dynSetLen(e, includeFilename, lg); // to be sure that \0 ends the filename
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ******** PUBLIC ********************* */
|
||||
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount)
|
||||
{
|
||||
if(!e || !directory || !fileFound || !fileFoundCount || !duplicateCount)
|
||||
return 0; // error
|
||||
@@ -81,9 +120,10 @@ long ScanDirectory(env * e, const char * path, Dynamic * directory, const char *
|
||||
#ifdef UNIX
|
||||
if((dir = opendir(workPath.mPtr)) == NULL)
|
||||
{
|
||||
// TODO ?! exit or continue to next item ?
|
||||
dynFree(e, &workPath);
|
||||
return 0;
|
||||
// continue to next item (no access right for example for this directory, etc.)
|
||||
//dynFree(e, &workPath);
|
||||
//return 0;
|
||||
continue;
|
||||
}
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
@@ -129,9 +169,10 @@ long ScanDirectory(env * e, const char * path, Dynamic * directory, const char *
|
||||
dynConcatSz(e, &workPath, "\\*", DYN_LGNONE); /* sinon ko... */
|
||||
if((hFind = FindFirstFile(workPath.mPtr, &FindFileData)) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// TODO ?! exit or continue to next item ?
|
||||
dynFree(e, &workPath);
|
||||
return 0;
|
||||
// continue to next item (no access right for example for this directory, etc.)
|
||||
//dynFree(e, &workPath);
|
||||
//return 0;
|
||||
continue;
|
||||
}
|
||||
dynSetLen(e, &workPath, workPath.mLg - 2); // enlever \* mis a la fin...
|
||||
for(int cr = -1;cr != 0;)
|
||||
@@ -188,62 +229,47 @@ long ScanDirectory(env * e, const char * path, Dynamic * directory, const char *
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int GetInclude(env * e, Dynamic * line, Dynamic * includeFilename)
|
||||
{
|
||||
// check that the <line> is a include w statement. If not, return zero, else
|
||||
// return in <includeFilename> the name of the include file
|
||||
// separators are 9 and 32 (tab and space) and ";"" for the optional end of line comment
|
||||
char * p = line->mPtr, * q;
|
||||
while(*p && (*p == 9 || *p == 32)) p++;
|
||||
if(*p++ != 'i') return 0;
|
||||
if(*p++ != 'n') return 0;
|
||||
if(*p++ != 'c') return 0;
|
||||
if(*p++ != 'l') return 0;
|
||||
if(*p++ != 'u') return 0;
|
||||
if(*p++ != 'd') return 0;
|
||||
if(*p++ != 'e') return 0;
|
||||
if(*p != 9 && *p != 32) return 0;
|
||||
p++;
|
||||
while(*p && (*p == 9 || *p == 32)) p++;
|
||||
q = p; // *p is the first char of include filename (except if *p is null)
|
||||
while(*q && (*q != 9 && *q != 32 && *q != ';')) q++;
|
||||
// *q is the last char of include filename
|
||||
if( (! *p) || *p == ';') return 0;
|
||||
if(*q == ';') q--;
|
||||
// find it : copy do includeFilename
|
||||
long lg = q - p + 1;
|
||||
dynLet(e, includeFilename, p, lg);
|
||||
dynSetLen(e, includeFilename, lg); // to be sure that \0 ends the filename
|
||||
dynErase(e, includeFilename, "'\"");
|
||||
return 1;
|
||||
}
|
||||
|
||||
long GetSource(env * e, const char * wsrc, const char * filename, Dynamic * source, Dynamic * meta)
|
||||
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta)
|
||||
{
|
||||
int cr = 0;
|
||||
char cLF = 10;
|
||||
char sLF[2] = {"\n"};
|
||||
char sCR[2] = {"\r"};
|
||||
dynSetLen(e, source, 0);
|
||||
dynSetLen(e, meta, 0);
|
||||
//
|
||||
Dynamic directory, fileFound, line, include, tmp;
|
||||
dynInit(e, &directory, DYN_LGMIN);
|
||||
Dynamic fileFound, line, include, filenameFound;
|
||||
dynInit(e, &fileFound, DYN_LGMIN);
|
||||
dynInit(e, &line, DYN_LGMIN);
|
||||
dynInit(e, &include, DYN_LGMIN);
|
||||
dynInit(e, &tmp, DYN_LGMIN);
|
||||
dynInit(e, &filenameFound, DYN_LGMIN);
|
||||
//
|
||||
long fileCount, dup;
|
||||
for(;;)
|
||||
{
|
||||
if(dynRead(e, source, (char *)filename) != DYN_OK)
|
||||
if( ScanDirectory(e, NULL, directory, filename, &fileFound, &fileCount, &dup) != 1)
|
||||
{
|
||||
cr = 1;
|
||||
break;
|
||||
if( ! ScanDirectory(e, wsrc, &directory, NULL, &fileFound, &fileCount, &dup))
|
||||
}
|
||||
if(fileCount != 1)
|
||||
{
|
||||
cr = 2;
|
||||
break;
|
||||
}
|
||||
if(dynRead(e, source, fileFound.mPtr) != DYN_OK)
|
||||
{
|
||||
cr = 3;
|
||||
break;
|
||||
}
|
||||
dynErase(e, source, sCR);
|
||||
//
|
||||
long level = 1, current = 1;
|
||||
dynStoreSz(e, meta, 1, DYN_NONE, "00000001", 8, cFM, DYN_NONE);
|
||||
dynStoreSz(e, meta, 2, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
|
||||
dynStoreSz(e, meta, 3, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
|
||||
long treeLevel = 1, currentLevel = 1, level = 0, nbMeta = 1;
|
||||
dynStoreSz(e, meta, META_GLOBAL_LN, DYN_NONE, "00000001", 8, cFM, DYN_NONE);
|
||||
dynStoreSz(e, meta, META_FILENAME, DYN_NONE, fileFound.mPtr, DYN_LGNONE, cFM, DYN_NONE);
|
||||
dynStoreSz(e, meta, META_LOCAL_LN, DYN_NONE, "1", DYN_LGNONE, cFM, DYN_NONE);
|
||||
dynStoreNumber(e, meta, META_LEVEL, DYN_NONE, currentLevel, cFM, DYN_NONE);
|
||||
dynStoreSz(e, meta, META_FILETREE, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
|
||||
// foreach source line
|
||||
long numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE);
|
||||
long numLine = 1;
|
||||
@@ -253,99 +279,126 @@ long GetSource(env * e, const char * wsrc, const char * filename, Dynamic * sour
|
||||
numLine++;
|
||||
if(GetInclude(e, &line, &include))
|
||||
{
|
||||
//printf("include: %s\n", include.mPtr);
|
||||
if(ScanDirectory(e, NULL, &directory, include.mPtr, &fileFound, &fileCount, &dup))
|
||||
if(ScanDirectory(e, NULL, directory, include.mPtr, &fileFound, &fileCount, &dup))
|
||||
{
|
||||
//printf("nb found %ld: %s\n", fileCount, fileFound.mPtr);
|
||||
if(fileCount == 1)
|
||||
{
|
||||
// memo include file tree to avoid cyclic includes and get meta data
|
||||
// 2 memos : one for call tree, and one for the map of files/number of lines
|
||||
// call tree =>
|
||||
// meta<3> = file tree, multi-valued filenames
|
||||
// meta<5> = file tree, multi-valued filenames (temporary, during GetSource)
|
||||
// meta data =>
|
||||
// meta<1> = beginning number of line
|
||||
// meta<1> = beginning line number, global
|
||||
// meta<2> = filename
|
||||
// meta<3> = local line number
|
||||
// meta<4> = level
|
||||
//
|
||||
// if filename already presents in file tree, error (ignore include)
|
||||
if(dynLocateSz(e, meta, fileFound.mPtr, cVM, 3, cFM) > 0)
|
||||
continue;
|
||||
// insert include file after include's line
|
||||
dynRead(e, &include, fileFound.mPtr);
|
||||
if(include.mLg == 0)
|
||||
continue; // don't insert empty file
|
||||
// suppress last character if LF : prevent blank line in result
|
||||
if(include.mPtr[include.mLg - 1] == cLF)
|
||||
dynSetLen(e, &include, include.mLg - 1);
|
||||
//
|
||||
// TODO : insert ENDINCLUDE pseudo code at the end of inserted include ? or only when generating pcode ! see with assembler.c
|
||||
dynIns(e, source, numLine, DYN_NONE, &include, cLF, DYN_NONE);
|
||||
long nbInclude = dynDcount(e, &include, cLF, DYN_NONE, DYN_NONE);
|
||||
numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE);
|
||||
//printf("inc ok %s nbinclude %ld nbline %ld current %ld\n", fileFound.mPtr, nbInclude, numberOfLines, numLine);
|
||||
// put in <include> the line number formatted 00000000 and split current block in three
|
||||
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
|
||||
long pos = abs(dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, 1, cFM));
|
||||
dynIns(e, meta, 1, pos, &include, cFM, cVM);
|
||||
dynIns(e, meta, 2, pos, &fileFound, cFM, cVM);
|
||||
//
|
||||
//dynExtractSubField(e, meta, 2, pos - 1, &include); // ko si separateurs changent...
|
||||
dynField(e, meta, &include, 2, pos - 1, cFM, cVM, 1);
|
||||
dynIns(e, meta, 2, pos + 1, &include, cFM, cVM);
|
||||
dynFmtNumber(e, numLine + nbInclude, &include, 'R', '0', 8);
|
||||
dynIns(e, meta, 1, pos + 1, &include, cFM, cVM);
|
||||
//
|
||||
// adjust starting line of next blocks
|
||||
long nbMeta = dynDcount(e, meta, cVM, 2, cFM);
|
||||
for(long cpt = pos + 2; cpt <= nbMeta; cpt++)
|
||||
dynField(e, &fileFound, &filenameFound, dynDcount(e, &fileFound, e->path_sep[0], DYN_NONE, DYN_NONE), DYN_NONE, e->path_sep[0], DYN_NONE, 1); // extract filename from full path
|
||||
if(dynLocateSz(e, meta, filenameFound.mPtr, cVM, META_FILETREE, cFM) > 0)
|
||||
{
|
||||
//long num = dynExtractSubFieldAsNumber(e, meta, 1, cpt, &include) + nbInclude;
|
||||
long num = dynFieldAsNumber(e, meta, 1, cpt, cFM, cVM) + nbInclude;
|
||||
dynFmtNumber(e, num, &include, 'R', '0', 8);
|
||||
dynStore(e, meta, 1, cpt, &include, cFM, cVM);
|
||||
cr = 4;
|
||||
break;
|
||||
}
|
||||
// insert include file after include's line
|
||||
if(include.mLg == 0) // don't insert empty file (else, local line number calculus wouldn't be correct), add one space instead
|
||||
{
|
||||
dynLet(e, &include, " ", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
dynErase(e, &include, sCR);
|
||||
if(include.mPtr[include.mLg - 1] != cLF)
|
||||
dynConcatSz(e, &include, sLF, 1); // add empty final line if there's not, else meta would have double same global line (if last line is include's line)
|
||||
}
|
||||
//
|
||||
dynStore(e, meta, 3, ++level, &fileFound, cFM, cVM);
|
||||
current++;
|
||||
dynIns(e, source, numLine, DYN_NONE, &include, cLF, DYN_NONE);
|
||||
long nbInclude = dynDcount(e, &include, cLF, DYN_NONE, DYN_NONE);
|
||||
numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE); // extending scope
|
||||
//
|
||||
// put in <include> the line number formatted 00000000 and split current block in three
|
||||
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
|
||||
long pos = abs(dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM));
|
||||
dynIns(e, meta, META_GLOBAL_LN, pos, &include, cFM, cVM);
|
||||
dynIns(e, meta, META_FILENAME, pos, &fileFound, cFM, cVM);
|
||||
dynInsSz(e, meta, META_LOCAL_LN, pos, "1", 1, cFM, cVM);
|
||||
level = dynFieldAsNumber(e, meta, META_LEVEL, pos - 1, cFM, cVM);
|
||||
dynInsNumber(e, meta, META_LEVEL, pos, level + 1, cFM, cVM);
|
||||
currentLevel = level + 1;
|
||||
//
|
||||
dynField(e, meta, &include, 2, pos - 1, cFM, cVM, 1);
|
||||
dynIns(e, meta, META_FILENAME, pos + 1, &include, cFM, cVM);
|
||||
dynFmtNumber(e, numLine + nbInclude, &include, 'R', '0', 8);
|
||||
dynIns(e, meta, META_GLOBAL_LN, pos + 1, &include, cFM, cVM);
|
||||
long global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, pos - 1, cFM, cVM);
|
||||
long local = dynFieldAsNumber(e, meta, META_LOCAL_LN, pos - 1, cFM, cVM);
|
||||
dynInsNumber(e, meta, META_LOCAL_LN, pos + 1, numLine - global + local, cFM, cVM);
|
||||
dynInsNumber(e, meta, META_LEVEL, pos + 1, level, cFM, cVM);
|
||||
//
|
||||
// adjust starting line of next blocks
|
||||
nbMeta = dynDcount(e, meta, cVM, META_FILENAME, cFM);
|
||||
for(long cpt = pos + 2; cpt <= nbMeta; cpt++)
|
||||
{
|
||||
global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, cpt, cFM, cVM);
|
||||
dynFmtNumber(e, global + nbInclude, &include, 'R', '0', 8);
|
||||
dynStore(e, meta, META_GLOBAL_LN, cpt, &include, cFM, cVM);
|
||||
}
|
||||
//
|
||||
dynStore(e, meta, META_FILETREE, ++treeLevel, &filenameFound, cFM, cVM);
|
||||
}
|
||||
else
|
||||
{
|
||||
cr = 5; // if fileCount <> 1, error (multiple included include not autorized, or not found when filename includes dot or path separator char)
|
||||
break;
|
||||
}
|
||||
// if fileCount > 1, error (ignore include)
|
||||
}
|
||||
// if error while searching for the include file, error (ignore include)
|
||||
else
|
||||
{
|
||||
cr = 6; // if error while searching for the include file, error
|
||||
break;
|
||||
}
|
||||
}
|
||||
// delete last file in call tree when changing of file
|
||||
// dynSetAsNumber(e, &tmp, numLine);
|
||||
//dynFmt(e, &tmp, &include, 'R', '0', 8); // TODO dynFmtNumber
|
||||
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
|
||||
long pos = dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, 1, cFM);
|
||||
if(pos != current && level > 0)
|
||||
{
|
||||
current = pos;
|
||||
dynDel(e, meta, 3, level--, cFM, cVM, 1);
|
||||
}
|
||||
long pos = dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM);
|
||||
if(pos < 0)
|
||||
pos = abs(pos) - 1;
|
||||
if(pos > nbMeta)
|
||||
pos = nbMeta;
|
||||
level = dynFieldAsNumber(e, meta, META_LEVEL, pos, cFM, cVM);
|
||||
if(level < currentLevel)
|
||||
dynDel(e, meta, META_FILETREE, treeLevel--, cFM, cVM, 1);
|
||||
currentLevel = level;
|
||||
}
|
||||
dynDel(e, meta, 3, DYN_NONE, cFM, DYN_NONE, 1);
|
||||
cr = 1;
|
||||
dynDel(e, meta, META_FILETREE, DYN_NONE, cFM, DYN_NONE, 1);
|
||||
break;
|
||||
}
|
||||
//
|
||||
dynFree(e, &directory);
|
||||
dynFree(e, &fileFound);
|
||||
dynFree(e, &line);
|
||||
dynFree(e, &include);
|
||||
dynFree(e, &tmp);
|
||||
dynFree(e, &filenameFound);
|
||||
return cr;
|
||||
}
|
||||
|
||||
void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound)
|
||||
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine)
|
||||
{
|
||||
indice *= 2;
|
||||
indice = (indice - 1) * META_NB;
|
||||
dynFmtNumber(e, lineNumber, fileFound, 'R', '0', 8);
|
||||
long pos = dynSortLocateSz(e, meta, fileFound->mPtr, cVM, DYN_SORT_ASC, indice - 1, cFM);
|
||||
long pos = dynSortLocateSz(e, meta, fileFound->mPtr, cVM, DYN_SORT_ASC, indice + META_GLOBAL_LN, cFM);
|
||||
if(pos < 0)
|
||||
{
|
||||
pos = abs(pos) - 1;
|
||||
if(pos < 1) pos = 1; // securite
|
||||
}
|
||||
dynSetLen(e, fileFound, 0);
|
||||
dynField(e, meta, fileFound, indice, pos, cFM, cVM, 1);
|
||||
//
|
||||
*ficLine = lineNumber - dynFieldAsNumber(e, meta, indice + META_GLOBAL_LN, pos, cFM, cVM) + dynFieldAsNumber(e, meta, indice + META_LOCAL_LN, pos, cFM, cVM);
|
||||
dynField(e, meta, fileFound, indice + META_FILENAME, pos, cFM, cVM, 1);
|
||||
}
|
||||
|
||||
WAPIDECL void GetTempDirectory(env * e, Dynamic * dir)
|
||||
{
|
||||
#ifdef WINLIB
|
||||
dynLet(e, dir, "C:\\Temp\\", DYN_LGNONE);
|
||||
#else
|
||||
dynLet(e, dir, "/tmp/", 5);
|
||||
#endif
|
||||
}
|
||||
@@ -23,10 +23,24 @@
|
||||
#ifndef REP_H
|
||||
#define REP_H
|
||||
|
||||
long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount);
|
||||
long GetSource(env * e, const char * wsrc, const char * filename, Dynamic * source, Dynamic * meta);
|
||||
#include "apidecl.h"
|
||||
|
||||
void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound);
|
||||
enum {
|
||||
META_GLOBAL_LN = 1,
|
||||
META_FILENAME = 2,
|
||||
META_LOCAL_LN = 3,
|
||||
META_LEVEL = 4,
|
||||
META_FILETREE = 5,
|
||||
META_WSRC = 5,
|
||||
META_NB = 5
|
||||
};
|
||||
|
||||
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount);
|
||||
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta);
|
||||
|
||||
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine);
|
||||
|
||||
WAPIDECL void GetTempDirectory(env * e, Dynamic * dir);
|
||||
|
||||
/* ********************************************** */
|
||||
#endif
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -25,11 +25,11 @@
|
||||
#include <string.h>
|
||||
|
||||
#ifndef WINLIB
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "langage.h"
|
||||
@@ -38,6 +38,12 @@
|
||||
typedef int key_t;
|
||||
#endif
|
||||
|
||||
/* codes a passer a la fonction setError */
|
||||
enum {
|
||||
EXMOD_BUFFER_INIT = 1,
|
||||
EXMOD_BUFFER_WRITE = 2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// proprietaire
|
||||
key_t cle;
|
||||
@@ -46,8 +52,11 @@ typedef struct {
|
||||
var * buffer;
|
||||
#ifndef WINLIB
|
||||
int handle;
|
||||
int semId;
|
||||
#else
|
||||
HANDLE handle;
|
||||
char semDesti[25]; // 23 cars + '#' + \0 (different desti sinon ko sous windows)
|
||||
HANDLE newProcess; // writer: handle process creee en SUSPEND, reader : handle passe en arg et convertit en num
|
||||
#endif
|
||||
// destinataire
|
||||
char desti[24]; // 23 cars + \0
|
||||
@@ -55,7 +64,7 @@ typedef struct {
|
||||
var * message;
|
||||
} modContextShm;
|
||||
|
||||
void initShm(env * e, modContextShm * ctx);
|
||||
void freeShm(env * e, modContextShm * ctx);
|
||||
void readShm(env * e, modContextShm * ctx);
|
||||
void writeShm(env * e, modContextShm * ctx);
|
||||
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);
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -27,108 +27,187 @@
|
||||
|
||||
#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;
|
||||
|
||||
#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_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)"
|
||||
};
|
||||
/* ============================================================================================= */
|
||||
|
||||
static int setError(modEtat * p, int err)
|
||||
{
|
||||
if(p != NULL)
|
||||
p->error = err;
|
||||
return err == OK ? OK : EX_MODERR;
|
||||
}
|
||||
#include "mod.c"
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
|
||||
modEtat * p_etat;
|
||||
long exc = OK;
|
||||
// init/end/vers/error sont obligatoires pour tout module
|
||||
// - - - - - - - - - - - - - - - - - - - -
|
||||
if(param == NULL || etat == NULL)
|
||||
/* 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(param->type == VAR_PARAM)
|
||||
param = (var *)param->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
|
||||
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(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
|
||||
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(param->type == VAR_NUMBER)
|
||||
param->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, "xxx", 3))
|
||||
else if(modFnIs(e, "get", 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 * paramContent = getParam(e, "content", 7);
|
||||
if(paramContent == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
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))
|
||||
{
|
||||
/* 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(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(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 = EX_MODFUNC; // fonction non prise en charge
|
||||
exc = EX_MODFUNC; /* unsupported function */
|
||||
}
|
||||
//
|
||||
return exc;
|
||||
}
|
||||
/* **************************************************************************************************** */
|
||||
@@ -23,10 +23,31 @@
|
||||
#include "shm.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "dynamic.h"
|
||||
#include <errno.h>
|
||||
|
||||
#define SHM_MIN_SIZE 1000
|
||||
#ifndef WINLIB
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
/* PRIVATE */
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
enum {
|
||||
NBSEM = 1
|
||||
};
|
||||
|
||||
/* ****** PRIVATE ************************ */
|
||||
static key_t Hash32(const char * cle, int lg)
|
||||
{
|
||||
// lg multiple de 4 et > 0
|
||||
@@ -58,36 +79,55 @@ static key_t Hash32(const char * cle, int lg)
|
||||
return (key_t)h;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------- */
|
||||
|
||||
void initShm(env * e, modContextShm * ctx)
|
||||
/* ****** PUBLIC ************************ */
|
||||
WAPIDECL void initShm(env * e, modContextShm * ctx)
|
||||
{
|
||||
#ifndef WINLIB
|
||||
ctx->buffer = NULL;
|
||||
ctx->handle = -1;
|
||||
ctx->semId = -1;
|
||||
// creer la sharedmemory du process, pour lecture
|
||||
if(ctx->taille < SHM_MIN_SIZE)
|
||||
return; // erreur buffer trop petit
|
||||
// ne pas controler la taille, sera fait par 'shmget'
|
||||
// calculer la cle a partir du nom du prog (ctx->nom)
|
||||
ctx->cle = Hash32(ctx->nom, 24); // chaine de 23 cars + \0
|
||||
ctx->cle = Hash32(ctx->nom, 24); // chaine de 23 cars max + \0 de fin
|
||||
// securite : supprimer un eventuel reliquat d'un ancien shm ? Faire un appel externe pas systematique, que le createur, (ou mettre un flag)
|
||||
//shmctl(ctx->cle, IPC_RMID, NULL);
|
||||
// creer le buffer
|
||||
ctx->handle = shmget(ctx->cle, ctx->taille, IPC_CREAT | IPC_EXCL | 0x666); // < 0 si ko
|
||||
ctx->handle = shmget(ctx->cle, ctx->taille, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
|
||||
if(ctx->handle < 0)
|
||||
return; // erreur creation sharedmemory
|
||||
// lire le pointeur
|
||||
ctx->buffer = (var *)shmat(ctx->handle, NULL, 0);
|
||||
if( ! ctx->buffer)
|
||||
if(ctx->buffer == (var *)(-1))
|
||||
{
|
||||
shmctl(ctx->handle, IPC_RMID, NULL);
|
||||
ctx->buffer = NULL;
|
||||
ctx->handle = -1;
|
||||
return; // erreur recup pointeur
|
||||
}
|
||||
// creer le semaphore pour les writers
|
||||
ctx->semId = semget(ctx->cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
|
||||
if(ctx->semId < 0)
|
||||
{
|
||||
freeShm(e, ctx); // erreur
|
||||
return;
|
||||
}
|
||||
// init semaphore
|
||||
unsigned short table[NBSEM];
|
||||
table[0] = 1;
|
||||
if(semctl(ctx->semId, 0, SETALL, table) < 0)
|
||||
{
|
||||
freeShm(e, ctx); // erreur
|
||||
return;
|
||||
}
|
||||
#else
|
||||
ctx->buffer = NULL;
|
||||
ctx->handle = NULL;
|
||||
strncpy(ctx->semDesti, ctx->desti, 24);
|
||||
ctx->semDesti[24] = 0;
|
||||
ctx->semDesti[strlen(ctx->desti)] = '#';
|
||||
// creer la sharedmemory du process, pour lecture
|
||||
if(ctx->taille < SHM_MIN_SIZE)
|
||||
return; // erreur buffer trop petit
|
||||
// ne pas controler la taille, sera fait par 'CreateFileMapping'
|
||||
// la cle est directement le nom
|
||||
// creer le buffer
|
||||
ctx->handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->taille, ctx->nom); // NULL si ko, attention au \0 de fin de ctx->nom
|
||||
@@ -97,6 +137,7 @@ void initShm(env * e, modContextShm * ctx)
|
||||
if( ! ctx->buffer)
|
||||
{
|
||||
CloseHandle(ctx->handle);
|
||||
ctx->buffer = NULL;
|
||||
ctx->handle = NULL;
|
||||
return; // erreur recup pointeur
|
||||
}
|
||||
@@ -105,31 +146,46 @@ void initShm(env * e, modContextShm * ctx)
|
||||
ctx->buffer->lgmax = ctx->taille - sizeof(var);
|
||||
ctx->buffer->read = 0;
|
||||
ctx->buffer->write = 0;
|
||||
ctx->buffer->ptr = (pointeur)ctx->buffer + sizeof(var); // le contenu est a la suite de l'entete de la variable
|
||||
ctx->buffer->ptr = NULL; // NULL signifie que le contenu est a la suite de l'entete de la variable (utilise uniquement ici avec les IPC)
|
||||
}
|
||||
|
||||
void freeShm(env * e, modContextShm * ctx)
|
||||
WAPIDECL void freeShm(env * e, modContextShm * ctx)
|
||||
{
|
||||
#ifndef WINLIB
|
||||
if(ctx->buffer)
|
||||
shmdt(ctx->buffer);
|
||||
if(ctx->handle >= 0)
|
||||
shmctl(ctx->handle, IPC_RMID, NULL);
|
||||
if(ctx->semId >= 0)
|
||||
semctl(ctx->semId, IPC_RMID, 0);
|
||||
ctx->buffer = NULL;
|
||||
ctx->handle = -1;
|
||||
ctx->semId = -1;
|
||||
#else
|
||||
if(ctx->buffer)
|
||||
UnmapViewOfFile(ctx->buffer);
|
||||
if(ctx->handle >= 0)
|
||||
CloseHandle(ctx->handle); // verif que bien detruit
|
||||
ctx->buffer = NULL;
|
||||
ctx->handle = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void readShm(env * e, modContextShm * ctx)
|
||||
WAPIDECL long readShm(env * e, modContextShm * ctx)
|
||||
{
|
||||
#ifndef WINLIB
|
||||
if( ! ctx->buffer || ctx->handle < 0)
|
||||
return EXMOD_BUFFER_INIT;
|
||||
#else
|
||||
if( ! ctx->buffer || ! ctx->handle)
|
||||
return EXMOD_BUFFER_INIT;
|
||||
#endif
|
||||
buffer_read(e, ctx->buffer, ctx->message);
|
||||
// e->exception != OK si exception en lecture (que EX_MEM) ! vide si rien a lire (Dynamic)
|
||||
return e->exception;
|
||||
}
|
||||
|
||||
void writeShm(env * e, modContextShm * ctx)
|
||||
WAPIDECL long writeShm(env * e, modContextShm * ctx)
|
||||
{
|
||||
#ifndef WINLIB
|
||||
// calculer la cle a partir du nom du prog (ctx->nom)
|
||||
@@ -137,39 +193,198 @@ void writeShm(env * e, modContextShm * ctx)
|
||||
// acceder au buffer
|
||||
int handle = shmget(cle, 0, 0);
|
||||
if(handle < 0)
|
||||
return; // erreur access
|
||||
return EXMOD_BUFFER_WRITE; // erreur access
|
||||
// lire le pointeur
|
||||
var * buffer = (var *)shmat(handle, NULL, 0);
|
||||
if( ! buffer)
|
||||
return; // seul le ptr se libere
|
||||
if(buffer == (var *)(-1))
|
||||
return EXMOD_BUFFER_WRITE; // seul le ptr se libere
|
||||
// prendre le verrou (semaphore) pour ecrire, avec attente
|
||||
int semId = semget(cle, NBSEM, 0);
|
||||
if(semId < 0)
|
||||
{
|
||||
shmdt(buffer);
|
||||
return EXMOD_BUFFER_WRITE;
|
||||
}
|
||||
struct sembuf bufw;
|
||||
bufw.sem_num = 0;
|
||||
bufw.sem_op = -1; // prendre
|
||||
bufw.sem_flg = SEM_UNDO; // | IPC_NOWAIT ?
|
||||
if(semop(semId, &bufw, 1) < 0)
|
||||
{
|
||||
shmdt(buffer);
|
||||
return EXMOD_BUFFER_WRITE;
|
||||
}
|
||||
// EcrireBuffer
|
||||
buffer_write(e, buffer, ctx->message);
|
||||
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
|
||||
// liberer le verrou
|
||||
bufw.sem_op = 1; // liberer
|
||||
semop(semId, &bufw, 1);
|
||||
// ne liberer que le ptr sous unix
|
||||
shmdt(buffer);
|
||||
#else
|
||||
// la cle est directement le destinataire
|
||||
HANDLE handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, ctx->desti); // attention au \0 de fin
|
||||
if( ! handle)
|
||||
return; // erreur access
|
||||
return EXMOD_BUFFER_WRITE; // erreur access
|
||||
// lire le pointeur
|
||||
var * buffer = (var *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if( ! buffer)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
return; // erreur recup pointeur
|
||||
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
|
||||
}
|
||||
// prendre le verrou (semaphore) pour ecrire, avec attente
|
||||
HANDLE hSem = CreateSemaphore(NULL, 1, 1, ctx->semDesti); // NULL si erreur
|
||||
if( ! hSem)
|
||||
{
|
||||
UnmapViewOfFile(buffer);
|
||||
CloseHandle(handle);
|
||||
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
|
||||
}
|
||||
if(WaitForSingleObject(hSem, 0) != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur ; 0 = timeout en secondes
|
||||
{
|
||||
ReleaseSemaphore(hSem, 1, NULL);
|
||||
UnmapViewOfFile(buffer);
|
||||
CloseHandle(handle);
|
||||
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
|
||||
}
|
||||
// EcrireBuffer
|
||||
buffer_write(e, buffer, ctx->message);
|
||||
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
|
||||
// liberer le verrou
|
||||
ReleaseSemaphore(hSem, 1, NULL);
|
||||
// liberations
|
||||
UnmapViewOfFile(buffer);
|
||||
CloseHandle(handle);
|
||||
#endif
|
||||
return e->exception;
|
||||
}
|
||||
|
||||
/*
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg); DispatchMessage(&msg);
|
||||
/* utilite ? */
|
||||
#ifndef WINLIB
|
||||
WAPIDECL int OpenLock(env * e, const char * name)
|
||||
{
|
||||
key_t cle = Hash32(name, 24); // chaine de 23 cars max + \0 de fin
|
||||
int semId = semget(cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666);
|
||||
if(semId < 0)
|
||||
{
|
||||
if(errno != EEXIST)
|
||||
return -1; // erreur
|
||||
// deja cree, ok
|
||||
semId = semget(cle, NBSEM, 0);
|
||||
if(semId < 0)
|
||||
{
|
||||
return -1; // erreur
|
||||
}
|
||||
}
|
||||
*/
|
||||
else
|
||||
{
|
||||
// init semaphore
|
||||
unsigned short table[NBSEM];
|
||||
table[0] = 1;
|
||||
if(semctl(semId, 0, SETALL, table) < 0)
|
||||
{
|
||||
semctl(semId, IPC_RMID, 0);
|
||||
return -1; // erreur
|
||||
}
|
||||
}
|
||||
return semId; // >=0 : ok
|
||||
}
|
||||
#else
|
||||
WAPIDECL HANDLE OpenLock(env * e, const char * name)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
sa.bInheritHandle = FALSE;
|
||||
|
||||
char fullName[40] = {0};
|
||||
if(strlen(name) > 23)
|
||||
return NULL; // nom trop long
|
||||
//
|
||||
strcpy(fullName, "Global\\");
|
||||
strcat(fullName, name);
|
||||
HANDLE hSem = CreateSemaphore(&sa, 1, 1, fullName); // 1 = valeur initiale du semaphore ; 1 = valeur max du semaphore ; nom du semaphore (unique)
|
||||
if( ! hSem)
|
||||
return NULL; // erreur (si existe, ne passe pas ici, hSem est renseigne avec le sem existant) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur, dans ce cas hSem n'est pas NULL
|
||||
else
|
||||
return hSem;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WINLIB
|
||||
WAPIDECL void CloseLock(env * e, int semId)
|
||||
{
|
||||
if(semId >= 0)
|
||||
semctl(semId, IPC_RMID, 0);
|
||||
}
|
||||
#else
|
||||
WAPIDECL void CloseLock(env * e, HANDLE hSem)
|
||||
{
|
||||
CloseHandle(hSem);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WINLIB
|
||||
WAPIDECL int SetLock(env * e, int semId, int milliSec)
|
||||
{
|
||||
// prendre le verrou (semaphore) pour ecrire, avec attente
|
||||
struct sembuf bufw;
|
||||
struct timespec ts;
|
||||
ts.tv_sec = milliSec / 1000;
|
||||
ts.tv_nsec = (milliSec % 1000) * 1000000; // xxx ms
|
||||
bufw.sem_num = 0;
|
||||
bufw.sem_op = -1; // prendre
|
||||
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
|
||||
if(semop(semId, &bufw, 1) < 0)
|
||||
{
|
||||
if(errno != EAGAIN)
|
||||
return -1; // erreur : semaphore ko
|
||||
// semaphore pris : attendre et reessayer une fois
|
||||
nanosleep(&ts, NULL);
|
||||
if(semop(semId, &bufw, 1) < 0)
|
||||
{
|
||||
if(errno != EAGAIN)
|
||||
return -1; // erreur : semaphore ko
|
||||
return 0; // sortie en timeout cette fois
|
||||
}
|
||||
}
|
||||
return 1; // ok
|
||||
}
|
||||
#else
|
||||
WAPIDECL int SetLock(env * e, HANDLE hSem, int milliSec)
|
||||
{
|
||||
int cr = WaitForSingleObject(hSem, milliSec);
|
||||
if( cr != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur
|
||||
{
|
||||
// semaphore pris : attendre ?
|
||||
if(cr != WAIT_TIMEOUT)
|
||||
return -1; // erreur
|
||||
// sortie en time out, semaphore pris, attendre ?
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef WINLIB
|
||||
WAPIDECL void UnsetLock(env * e, int semId)
|
||||
{
|
||||
// liberer le verrou
|
||||
struct sembuf bufw;
|
||||
bufw.sem_num = 0;
|
||||
bufw.sem_op = 1; // liberer
|
||||
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
|
||||
semop(semId, &bufw, 1);
|
||||
}
|
||||
#else
|
||||
WAPIDECL void UnsetLock(env * e, HANDLE hSem)
|
||||
{
|
||||
// liberer le semaphore
|
||||
ReleaseSemaphore(hSem, 1, NULL);
|
||||
}
|
||||
#endif
|
||||
@@ -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 <stdio.h>
|
||||
#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 Socket * wPoll;
|
||||
#endif
|
||||
|
||||
/* codes a passer a la fonction setError */
|
||||
enum {
|
||||
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 {
|
||||
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
|
||||
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 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 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 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);
|
||||
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -25,487 +25,583 @@
|
||||
#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
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netdb.h>
|
||||
#ifdef WINLIB
|
||||
#include "winsock2.h"
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include "windows.h"
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netdb.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 */
|
||||
//***
|
||||
long mSocket; /* socket en cours */
|
||||
int mServeur; /* 0 socket serveur mere en ecoute, 1 socket serveur fille connectee a un client, 2 socket client */
|
||||
#ifdef UNIX
|
||||
sigset_t mOldBlockSig,mBlockSig; /* gestion des signaux sur socket serveur en ecoute */
|
||||
#endif
|
||||
// TODO : gerer plusieurs sockets (serveur ? client ?)
|
||||
int error; // dernier code erreur specifique au module
|
||||
//*** a completer selon le besoin du module
|
||||
modContextSocket ctxSock;
|
||||
} 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_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_SOCK_WAIT_TIMEOUT = 13,
|
||||
EXMOD_NB = 13
|
||||
};
|
||||
/* 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"
|
||||
};
|
||||
/* ============================================================================================= */
|
||||
|
||||
static int setError(modEtat * p, int err)
|
||||
{
|
||||
if(p != NULL)
|
||||
p->error = err;
|
||||
return EX_MODERR;
|
||||
}
|
||||
#include "mod.c"
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
|
||||
modEtat * p_etat;
|
||||
long exc = OK;
|
||||
// init/end/vers/error sont obligatoires pour tout module
|
||||
// fonction createServer, arret
|
||||
// - - - - - - - - - - - - - - - - - - - -
|
||||
if(param == NULL || etat == NULL)
|
||||
/* init/end/vers/error sont obligatoires pour tout module */
|
||||
if(etat == NULL)
|
||||
return EX_MODPARAM;
|
||||
else
|
||||
else
|
||||
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
|
||||
if(param->type == VAR_PARAM)
|
||||
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
|
||||
//
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
/* 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;
|
||||
//***
|
||||
p_etat->mSocket = 0;
|
||||
p_etat->mServeur = 0;
|
||||
// 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(strncmp(e->fn, "end", 3) == 0)
|
||||
else if(modFnIs(e, "end", 3))
|
||||
{
|
||||
// liberation specifique au module avant arret process
|
||||
p_etat = (modEtat *)(*etat);
|
||||
if(p_etat != NULL)
|
||||
{
|
||||
//***
|
||||
if(p_etat->mSocket > 0)
|
||||
close(p_etat->mSocket);
|
||||
//***
|
||||
//*** code specifique ici
|
||||
freeSock(e, &p_etat->ctxSock);
|
||||
/* ============ here ============ */
|
||||
// liberation du module avant arret process
|
||||
memfree(e, p_etat);
|
||||
}
|
||||
}
|
||||
else if(strncmp(e->fn, "vers", 4) == 0)
|
||||
else if(p_etat == NULL)
|
||||
{
|
||||
// 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
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
exc = EX_MODETAT;
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
var * paramVersion = getParam(e, "version", 7);
|
||||
if(paramVersion == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
if(param->type == VAR_NUMBER)
|
||||
param->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(strncmp(e->fn, "server", 6) == 0)
|
||||
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, param, 0, 5);
|
||||
if(param->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;
|
||||
}
|
||||
/* get param in the right order */
|
||||
var * paramPortNumber = getParam(e, "portNumber", 10);
|
||||
var * paramLocalSocket = getParam(e, "localSocket", 11);
|
||||
/* */
|
||||
#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
|
||||
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;
|
||||
}
|
||||
if((paramPortNumber == NULL && paramLocalSocket == NULL) ||
|
||||
(paramPortNumber != NULL && paramLocalSocket != NULL) )
|
||||
exc = EX_MODPARAM;
|
||||
else if((paramPortNumber != NULL && paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC) ||
|
||||
(paramLocalSocket != NULL && paramLocalSocket->type != VAR_NUMBER && paramLocalSocket->type != VAR_DYNAMIC) )
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
if(listen(p_etat->mSocket, 10) < 0)
|
||||
{
|
||||
/* cree un point d'entree serveur */
|
||||
number port = 0;
|
||||
var * local = NULL;
|
||||
if(paramLocalSocket != NULL)
|
||||
{
|
||||
close(p_etat->mSocket); /* erreur */
|
||||
exc = setError(p_etat, 1);
|
||||
p_etat->mSocket = 0;
|
||||
return exc;
|
||||
GetTempDirectory(e, &e->tmp_dynamic);
|
||||
if(paramLocalSocket->type == VAR_NUMBER)
|
||||
dynConcatNumber(e, &e->tmp_dynamic, paramLocalSocket->num / NUM_FACTEUR);
|
||||
else
|
||||
dynConcat(e, &e->tmp_dynamic, paramLocalSocket);
|
||||
local = &e->tmp_dynamic;
|
||||
}
|
||||
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( ! 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 */
|
||||
}
|
||||
if(exc == OK)
|
||||
{
|
||||
if(NewSocket(e, &p_etat->ctxSock, (local != NULL)) == WSOCKET_OK)
|
||||
{
|
||||
if(SocketSetServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), local) != WSOCKET_OK)
|
||||
exc = setError(p_etat, EXMOD_SOCK_SETSERVER);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_SOCK_NEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "connect", 7) == 0)
|
||||
else if(modFnIs(e, "connect", 7))
|
||||
{
|
||||
char ** tParam;
|
||||
/* connexion a un serveur */
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(dynDcount(e, param, cFM, DYN_NONE, DYN_NONE) < 2)
|
||||
/* 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 * paramLocalSocket = getParam(e, "localSocket", 11);
|
||||
/* */
|
||||
if(paramHost == NULL || paramSocket == NULL || (paramPortNumber == NULL && paramLocalSocket == NULL) ||
|
||||
(paramPortNumber != NULL && paramLocalSocket != NULL) )
|
||||
exc = EX_MODPARAM;
|
||||
else if(paramHost->type != VAR_DYNAMIC || (paramPortNumber != NULL && paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC) ||
|
||||
(paramLocalSocket != NULL && paramLocalSocket->type != VAR_NUMBER && paramLocalSocket->type != VAR_DYNAMIC) )
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
/* connexion a un serveur */
|
||||
number port = 0;
|
||||
var * local = NULL;
|
||||
if(paramLocalSocket != NULL)
|
||||
{
|
||||
GetTempDirectory(e, &e->tmp_dynamic);
|
||||
if(paramLocalSocket->type == VAR_NUMBER)
|
||||
dynConcatNumber(e, &e->tmp_dynamic, paramLocalSocket->num / NUM_FACTEUR);
|
||||
else
|
||||
dynConcat(e, &e->tmp_dynamic, paramLocalSocket);
|
||||
local = &e->tmp_dynamic;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ! var_conv_num(e, paramPortNumber, &port))
|
||||
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM);
|
||||
}
|
||||
if(exc == OK)
|
||||
{
|
||||
if(NewSocket(e, &p_etat->ctxSock, (local != NULL)) == WSOCKET_OK)
|
||||
{
|
||||
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), local, 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, "stopServer", 10))
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
/* 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, "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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
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
|
||||
{
|
||||
// param<1> = host (nom ou ip)
|
||||
// param<2> = port
|
||||
// decouper en 2 chaines Comm
|
||||
tParam = dynToTabPtr(e, param, cFM);
|
||||
if(tParam == NULL)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
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
|
||||
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;
|
||||
}
|
||||
if(exc != OK)
|
||||
return exc;
|
||||
long port = atoi(tParam[1]);
|
||||
if(param->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
|
||||
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 if(modFnIs(e, "set", 3))
|
||||
{
|
||||
/* 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((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
else
|
||||
{
|
||||
p_etat->mServeur = 2; /* client */
|
||||
#ifdef UNIX
|
||||
sigemptyset(&p_etat->mOldBlockSig);
|
||||
sigfillset(&p_etat->mBlockSig);
|
||||
number socket;
|
||||
if( var_conv_num(e, paramSocket, &socket) )
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#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(strncmp(e->fn, "arret", 5) == 0)
|
||||
else if(modFnIs(e, "export", 6))
|
||||
{
|
||||
/* arret connexion cliente ou serveur */
|
||||
if(p_etat != NULL)
|
||||
/* get param in the right order */
|
||||
var * paramSocket = getParam(e, "socket", 6);
|
||||
var * paramPid = getParam(e, "pid", 3);
|
||||
var * paramClose = getParam(e, "closeOnSend", 11);
|
||||
/* envoi d'une socket a un autre process via son pid, par socket unix locale (non secu) */
|
||||
if(paramSocket == NULL || paramPid == NULL || paramClose == NULL)
|
||||
exc = EX_MODPARAM;
|
||||
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || (paramPid->type != VAR_NUMBER && paramPid->type != VAR_DYNAMIC) ||
|
||||
(paramClose->type != VAR_NUMBER && paramClose->type != VAR_DYNAMIC) )
|
||||
exc = EX_MODPARAM;
|
||||
else
|
||||
{
|
||||
shutdown(p_etat->mSocket, 2);
|
||||
close(p_etat->mSocket);
|
||||
p_etat->mSocket = 0;
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "attente", 7) == 0)
|
||||
{
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(param == NULL)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
else if(param->type != VAR_NUMBER)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
if(exc == OK)
|
||||
{
|
||||
fd_set masque;
|
||||
struct timeval delai;
|
||||
long cr;
|
||||
// attend une activite sur la socket, timeOut en 1/10 de sec.
|
||||
delai.tv_sec = param->num / NUM_FACTEUR; // x sec
|
||||
delai.tv_usec = (param->num % NUM_FACTEUR) * 10; // y µsec
|
||||
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 socket, pid, closeOnSend;
|
||||
if( ! var_conv_num(e, paramSocket, &socket) || ! var_conv_num(e, paramPid, &pid) || ! var_conv_num(e, paramClose, &closeOnSend))
|
||||
exc = setError(p_etat, 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(cr > 0)
|
||||
param->num = NUM_UN; /* ok pour lire */
|
||||
else
|
||||
param->num = NUM_ZERO; /* pas de donnees */
|
||||
// si cr > 0 : ok pour continuer et lire la socket
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "get", 3) == 0)
|
||||
{
|
||||
long nblu = 0, arg = 1, flagInProgress = 0, pas = 16000, would_block;
|
||||
/* lecture sur la connexion */
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(param == NULL)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
else if(param->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
if(exc == OK)
|
||||
{
|
||||
// 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, param, 0);
|
||||
do
|
||||
{
|
||||
if(!dynCtrl(e, param, param->mLg + pas, 1)) /* avec recopie */
|
||||
if(NewSocket(e, &p_etat->ctxSock, TRUE) == WSOCKET_OK)
|
||||
{
|
||||
exc = setError(p_etat, 1);
|
||||
break;
|
||||
GetTempDirectory(e, &e->tmp_dynamic);
|
||||
dynConcatSz(e, &e->tmp_dynamic, "wsocket_", 8);
|
||||
dynConcatNumber(e, &e->tmp_dynamic, pid / NUM_FACTEUR);
|
||||
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, 0, &e->tmp_dynamic, NULL) == WSOCKET_OK)
|
||||
{
|
||||
/* si socket donnee = 0, envoyer la socket serveur */
|
||||
if(SendSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, socket == 0 ? p_etat->ctxSock.servSock : socket, pid / NUM_FACTEUR) == OK)
|
||||
{
|
||||
dynSetLen(e, &e->tmp_dynamic, 0);
|
||||
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" */
|
||||
if(dynCompare(e, &e->tmp_dynamic, CMP_NE, "OK", 2))
|
||||
exc = setError(p_etat, EXMOD_SOCK_READ);
|
||||
/* socket bien recue par l'autre process : fermer celle ici si besoin */
|
||||
else if(closeOnSend)
|
||||
FreeSocket(e, &p_etat->ctxSock, socket == 0 ? p_etat->ctxSock.servSock : socket);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_SOCK_READ);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_SOCK_WRITE);
|
||||
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock);
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_SOCK_CONNECT);
|
||||
}
|
||||
would_block = 0;
|
||||
while((nblu = read(p_etat->mSocket, param->mPtr + param->mLg, pas)) < 0 && errno == EWOULDBLOCK /* WouldBlock = 11 */
|
||||
&& (param->mLg == 0 || flagInProgress) && (++would_block) < 100)
|
||||
#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, param, param->mLg + nblu);
|
||||
/* */
|
||||
} while (nblu > 0);
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "set", 3) == 0)
|
||||
{
|
||||
long nb , pos = 0, lg, would_block;
|
||||
/* ecriture sur la connexion */
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(param == NULL)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
else if(param->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
if(exc == OK)
|
||||
{
|
||||
lg = param->mLg;
|
||||
while(lg > 0)
|
||||
{
|
||||
would_block = 0;
|
||||
while((nb = write(p_etat->mSocket, param->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)
|
||||
{
|
||||
exc = setError(p_etat, 2);
|
||||
break;
|
||||
}
|
||||
lg -= nb;
|
||||
if(lg > 0)
|
||||
pos += nb; /* ecriture en plusieurs fois */
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_SOCK_NEW);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "accept", 6) == 0)
|
||||
else if(modFnIs(e, "import", 6))
|
||||
{
|
||||
/* ecriture sur la connexion */
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
else if(param == NULL)
|
||||
exc = EX_MODPARAM; /* erreur */
|
||||
else if(param->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)
|
||||
param->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)
|
||||
exc = setError(p_etat, EXMOD_SOCK_WAIT_TIMEOUT);
|
||||
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
|
||||
{
|
||||
/* ecriture cr KO, mais socket recue => dans le doute, fermer la socket quand meme */
|
||||
FreeSocket(e, &p_etat->ctxSock, socket);
|
||||
exc = setError(p_etat, EXMOD_SOCK_WRITE);
|
||||
}
|
||||
}
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_SOCK_READ);
|
||||
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
|
||||
param->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;
|
||||
}
|
||||
+824
@@ -0,0 +1,824 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include "sock.h"
|
||||
|
||||
#include "dynamic.h"
|
||||
#include <errno.h>
|
||||
|
||||
#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
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
/* ****** 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)
|
||||
{
|
||||
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;
|
||||
WSAStartup(MAKEWORD(2,2), &wsa);
|
||||
#endif
|
||||
}
|
||||
|
||||
WAPIDECL void freeSock(env * e, modContextSocket * ctx)
|
||||
{
|
||||
/* 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 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);
|
||||
int iOptVal = 0;
|
||||
int iOptLen = sizeof(int);
|
||||
u_long block_mode = 1; // 1 = non-bloquant, 0 = bloquant
|
||||
#else
|
||||
int sockopt = 1; // 1 = non-bloquant, 0 = bloquant
|
||||
#endif
|
||||
struct linger l_s; /* Structure pour setsockopt */
|
||||
Socket sock;
|
||||
/* */
|
||||
if(local)
|
||||
{
|
||||
/* socket "Unix" (local a une machine) */
|
||||
#ifndef WINLIB
|
||||
if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
#else
|
||||
if((sock = WSASocket(AF_UNIX, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT)) == INVALID_SOCKET)
|
||||
#endif
|
||||
{
|
||||
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 WSOCKET_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)))
|
||||
{
|
||||
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(bind(sock, sa, sofsa) < 0)
|
||||
#else
|
||||
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
|
||||
DeleteLocalSocketFile(e, ctx);
|
||||
return WSOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx)
|
||||
{
|
||||
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;
|
||||
/* 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(localPath->mLg >= sizeof(addr.sun_path))
|
||||
return WSOCKET_ERROR;
|
||||
/* */
|
||||
strcpy(addr.sun_path, localPath->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};
|
||||
union {
|
||||
char buffer[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr align;
|
||||
} u;
|
||||
memset(u.buffer, 0, sizeof(u.buffer));
|
||||
char buf_data = 'X';
|
||||
struct iovec io = {
|
||||
.iov_base = &buf_data,
|
||||
.iov_len = 1
|
||||
};
|
||||
msg.msg_iov = &io;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = u.buffer;
|
||||
msg.msg_controllen = sizeof(u.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};
|
||||
union {
|
||||
char buffer[CMSG_SPACE(sizeof(int))];
|
||||
struct cmsghdr align;
|
||||
} u;
|
||||
memset(u.buffer, 0, sizeof(u.buffer));
|
||||
char buf_data;
|
||||
struct iovec io = {
|
||||
.iov_base = &buf_data,
|
||||
.iov_len = 1
|
||||
};
|
||||
msg.msg_iov = &io;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = u.buffer;
|
||||
msg.msg_controllen = sizeof(u.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));
|
||||
/* */
|
||||
#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;
|
||||
#endif
|
||||
/* socket recu = socket serveur forcement */
|
||||
if(AddSocket(e, ctx, *socketReceived) == WSOCKET_OK)
|
||||
{
|
||||
FreeSocket(e, ctx, ctx->servSock); /* securite : libere l'ancien socket server */
|
||||
ctx->servSock = *socketReceived;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#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
|
||||
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
|
||||
}
|
||||
|
||||
WAPIDECL long WaitSocketForRead(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 = 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)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
WAPIDECL int GetSocketError()
|
||||
{
|
||||
#ifdef WINLIB
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
WAPIDECL int SocketWouldBlock()
|
||||
{
|
||||
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(;;)
|
||||
{
|
||||
/* TODO : mettre une limite en nb octets lus ? */
|
||||
int cr = WaitOneSocketForRead(e, ctx, sock, timeoutMs);
|
||||
if(cr < 0)
|
||||
{
|
||||
if(SocketWouldBlock())
|
||||
continue;
|
||||
ctx->err = GetSocketError();
|
||||
return WSOCKET_ERROR; /* erreur */
|
||||
}
|
||||
if(cr == 0)
|
||||
return WSOCKET_OK; /* timeout : renvoi des donnees eventuellement deja lues */
|
||||
/* */
|
||||
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
|
||||
{
|
||||
return WSOCKET_MEM_ERROR; // erreur memoire
|
||||
}
|
||||
#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(SocketWouldBlock())
|
||||
continue;
|
||||
ctx->err = GetSocketError();
|
||||
return WSOCKET_ERROR; /* erreur */
|
||||
}
|
||||
if(nbRead == 0 && nbTot == 0)
|
||||
return WSOCKET_END_CONNECT; /* fin de lecture car fin de la comm - A REVOIR */
|
||||
/* nbRead positif ici */
|
||||
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)
|
||||
{
|
||||
long len = data->mLg, nbTot = 0, timeoutMs = 1000;
|
||||
if(len == 0)
|
||||
return WSOCKET_OK;
|
||||
/* */
|
||||
for(;;)
|
||||
{
|
||||
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(SocketWouldBlock())
|
||||
continue;
|
||||
ctx->err = GetSocketError();
|
||||
return WSOCKET_ERROR; /* erreur */
|
||||
}
|
||||
len -= nbWrite;
|
||||
nbTot += nbWrite;
|
||||
if(len <= 0)
|
||||
return WSOCKET_OK;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
+507
@@ -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
|
||||
*/
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+341
-312
@@ -2,7 +2,7 @@
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024,2025 lanisys.fr
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
@@ -25,157 +25,207 @@
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef UNIX
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include "windows.h" // TODO ici
|
||||
#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 */
|
||||
#define EXMOD_SYSTEM_FICTMP 1
|
||||
#define EXMOD_SYSTEM_UNKNOWNVARENV 2
|
||||
#define EXMOD_SYSTEM_SETENV 3
|
||||
#define EXMOD_SYSTEM_UNSETENV 4
|
||||
#define EXMOD_SYSTEM_GETHOST 5
|
||||
#define EXMOD_SYSTEM_UNAME 6
|
||||
#define EXMOD_SYSTEM_FORK 7
|
||||
enum {
|
||||
EXMOD_SYSTEM_FICTMP = 1,
|
||||
EXMOD_SYSTEM_UNKNOWNVARENV = 2,
|
||||
EXMOD_SYSTEM_SETENV = 3,
|
||||
EXMOD_SYSTEM_UNSETENV = 4,
|
||||
EXMOD_SYSTEM_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"
|
||||
|
||||
#ifndef UNIX
|
||||
#ifdef WINLIB
|
||||
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
|
||||
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#else
|
||||
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
#endif
|
||||
|
||||
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
|
||||
{
|
||||
modEtat * p_etat;
|
||||
long exc = OK;
|
||||
// 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 */
|
||||
if(strncmp(e->fn, "init", 4) == 0)
|
||||
/* 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(strncmp(e->fn, "end", 3) == 0)
|
||||
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(strncmp(e->fn, "vers", 4) == 0)
|
||||
else if(p_etat == NULL)
|
||||
{
|
||||
// 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;
|
||||
else
|
||||
exc = EX_MODPARAM; // variable en parametre du mauvais type
|
||||
exc = EX_MODETAT;
|
||||
}
|
||||
else if(strncmp(e->fn, "error", 5) == 0)
|
||||
else if(modFnIs(e, "vers", 4))
|
||||
{
|
||||
// renvoie la derniere erreur specifique au module
|
||||
if(p_etat == NULL)
|
||||
exc = EX_MODETAT;
|
||||
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(strncmp(e->fn, "execute", 7) == 0)
|
||||
else if(modFnIs(e, "execute", 7))
|
||||
{
|
||||
p_etat->error = 0;
|
||||
// execute(command, returning, capturing)
|
||||
// pour les vars en sortie, forcer le chgt de type si besoin ?
|
||||
if(!param1 || 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
|
||||
@@ -184,308 +234,287 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
|
||||
{
|
||||
if(flagCapturing)
|
||||
{
|
||||
dynIns(e, &e->int_dynamic, 1, DYN_NONE, param3, '>', DYN_NONE);
|
||||
cr = system(param1->mPtr);
|
||||
dynRead(e, param3, e->int_dynamic.mPtr);
|
||||
// TODO : purge fichier temp ?
|
||||
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(strncmp(e->fn, "getEnv", 6) == 0)
|
||||
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(strncmp(e->fn, "createEnv", 9) == 0)
|
||||
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(strncmp(e->fn, "updateEnv", 9) == 0)
|
||||
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(strncmp(e->fn, "deleteEnv", 9) == 0)
|
||||
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(strncmp(e->fn, "getOS", 5) == 0)
|
||||
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(strncmp(e->fn, "getHostname", 5) == 0)
|
||||
else if(modFnIs(e, "sendSignal", 10))
|
||||
{
|
||||
p_etat->error = 0;
|
||||
// uname() donne les infos
|
||||
if(param1->type != VAR_DYNAMIC)
|
||||
exc = EX_MODPARAM;
|
||||
else if(param2->type != VAR_DYNAMIC)
|
||||
/* 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
|
||||
{
|
||||
#ifdef WINLIB
|
||||
DWORD size = param1->mLgmax;
|
||||
if (!GetComputerNameA(param1->mPtr, &size))
|
||||
number pid, numSignal;
|
||||
if( var_conv_num(e,paramPid, &pid) && var_conv_num(e, paramSignalNumber, &numSignal) )
|
||||
{
|
||||
exc = EXMOD_SYSTEM_GETHOST;
|
||||
setError(p_etat, errno);
|
||||
pid /= NUM_FACTEUR;
|
||||
numSignal /= NUM_FACTEUR;
|
||||
#ifdef WINLIB
|
||||
// faire differemment sous windows : pas de kill dispo, passer par des evenements (GenerateConsoleCtrlEvent ne fonctionne pas si autre session/cmd/BACK...)
|
||||
#define SIGINT 2
|
||||
#define SIGUSR1 10
|
||||
#define SIGTERM 15
|
||||
// autoriser tous les process a inter agir...
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
||||
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
|
||||
sa.nLength = sizeof(sa);
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
sa.bInheritHandle = FALSE;
|
||||
//
|
||||
HANDLE hEvent = NULL;
|
||||
char eventName[40] = {0};
|
||||
if(numSignal == SIGTERM || numSignal == SIGINT)
|
||||
{
|
||||
sprintf(eventName, "Global\\wterm%lld", pid);
|
||||
hEvent= CreateEvent(&sa, FALSE, FALSE, eventName);
|
||||
}
|
||||
else if(numSignal == SIGUSR1)
|
||||
{
|
||||
sprintf(eventName, "Global\\wdebug%lld", pid);
|
||||
hEvent = CreateEvent(&sa, FALSE, FALSE, eventName);
|
||||
}
|
||||
if(hEvent != NULL) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur : l'event existe deja (et hEvent n'est pas NULL)
|
||||
{
|
||||
// envoyer le signal
|
||||
SetEvent(hEvent);
|
||||
CloseHandle(hEvent);
|
||||
}
|
||||
//
|
||||
#else
|
||||
if(numSignal == SIGTERM || numSignal == SIGINT || numSignal == SIGUSR1)
|
||||
kill(pid, numSignal);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
exc = EX_MODPARAM;
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "fork", 4) == 0)
|
||||
else if(modFnIs(e, "sleep", 5))
|
||||
{
|
||||
p_etat->error = 0;
|
||||
#ifndef UNIX
|
||||
// faire differemment sous windows : pas de fork dispo ? CreateProcess()
|
||||
#else
|
||||
pid_t fils = fork();
|
||||
if(fils == -1)
|
||||
/* 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))
|
||||
{
|
||||
exc = EXMOD_SYSTEM_FORK;
|
||||
setError(p_etat, errno);
|
||||
#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;
|
||||
}
|
||||
}
|
||||
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 = NULL, * ve = NULL;
|
||||
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_WARGV), &va); // garder {1,1} = executeur W
|
||||
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_ENV), &ve); // wbin wsrc wlib {1,1-3}
|
||||
if(va && ve)
|
||||
{
|
||||
if(fils == 0)
|
||||
e->ppid = 0; // process fils
|
||||
else
|
||||
e->ppid = fils; // process pere
|
||||
dynField(e, va, &e->tmp_dynamic, 1, DYN_NONE, cVM, DYN_NONE, 1);
|
||||
dynStore(e, &e->tmp_dynamic, 2, DYN_NONE, ve, cVM, DYN_NONE); /* tmp_dynamic = execw wbin wsrc wlib en VM */
|
||||
dynReplace(e, &e->tmp_dynamic, cVM, cFM);
|
||||
dynConcatSz(e, &e->tmp_dynamic, sFM, 1);
|
||||
dynConcat(e, &e->tmp_dynamic, paramArgs); /* tmp_dynamic = execw wbin wsrc wlib progw argw1 etc. en FM */
|
||||
dynInsSz(e, &e->tmp_dynamic, 2, 1, "-WBIN", 5, cFM, ':');
|
||||
dynInsSz(e, &e->tmp_dynamic, 3, 1, "-WSRC", 5, cFM, ':');
|
||||
dynInsSz(e, &e->tmp_dynamic, 4, 1, "-WLIB", 5, cFM, ':');
|
||||
dynInsSz(e, &e->tmp_dynamic, 5, DYN_NONE, "-b", 2, cFM, DYN_NONE); /* indique aux fils que deja lance en background */
|
||||
/* tmp_dynamic contient la ligne de commande complete */
|
||||
#ifdef WINLIB
|
||||
dynReplace(e, &e->tmp_dynamic, cFM, ' '); /* recree une ligne de commande */
|
||||
STARTUPINFO si = {0};
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
si.cb = sizeof(si);
|
||||
if(CreateProcess(NULL, e->tmp_dynamic.mPtr, NULL, NULL, FALSE, e->demon ? CREATE_NO_WINDOW : DETACHED_PROCESS, NULL, NULL, &si, &pi)) // ou DETACHED_PROCESS comme avec BACK !? (CREATE_NEW_CONSOLE lance une console !)
|
||||
{
|
||||
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, &e->tmp_dynamic, &e->int_dynamic, 1, DYN_NONE, cFM, DYN_NONE, 1);
|
||||
char ** argv = dynToTabPtr(e, &e->tmp_dynamic, cFM);
|
||||
execvp(e->int_dynamic.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
|
||||
}
|
||||
#endif
|
||||
else
|
||||
exc = setError(p_etat, EXMOD_CMDLINE_ARG);
|
||||
}
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "wait", 4) == 0)
|
||||
{
|
||||
#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(strncmp(e->fn, "kill", 4) == 0)
|
||||
{
|
||||
#ifndef UNIX
|
||||
// faire differemment sous windows : pas de kill dispo ?
|
||||
#else
|
||||
kill(0, SIGTERM); // envoi un signal de fin a tous les fils
|
||||
#endif
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
else if(strncmp(e->fn, "sleep", 5) == 0)
|
||||
{
|
||||
#ifdef WINLIB
|
||||
if(param1->type != VAR_NUMBER)
|
||||
exc = EX_MODPARAM;
|
||||
// duree attente envoyee en secondes
|
||||
Sleep(param1->num * 1000 / NUM_FACTEUR); // en millisec.
|
||||
#else
|
||||
if(param1->type != VAR_NUMBER)
|
||||
exc = EX_MODPARAM;
|
||||
// duree attente envoyee en secondes, avec les decimales
|
||||
usleep(param1->num * (1000000 / NUM_FACTEUR)); // en microsec.
|
||||
#endif
|
||||
}
|
||||
/* ----------------------------------------------------------------------------------------------- */
|
||||
/* ============================================================================================= */
|
||||
else
|
||||
{
|
||||
setError(p_etat, 0);
|
||||
exc = EX_MODFUNC; // fonction non prise en charge
|
||||
exc = EX_MODFUNC; /* unsupported function */
|
||||
}
|
||||
//
|
||||
return exc;
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / 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"
|
||||
|
||||
/* ============================================================================================= */
|
||||
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_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"
|
||||
};
|
||||
/* ============================================================================================= */
|
||||
|
||||
#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, "xxx", 3))
|
||||
{
|
||||
/* 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
|
||||
{
|
||||
exc = EX_MODFUNC; /* unsupported function */
|
||||
}
|
||||
return exc;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* **********************************************
|
||||
__ __ __
|
||||
\ \/ \/ / W language
|
||||
\ /\ /
|
||||
\/ \/ Copyright 2024-2026 lanisys.fr
|
||||
|
||||
This file is part of W language.
|
||||
|
||||
W language is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version (GPL-3.0-or-later).
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
********************************************** */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "langage.h"
|
||||
#include "dynamic.h"
|
||||
#include "var.h"
|
||||
|
||||
/* programme de test unitaire de lib/fonctions */
|
||||
/* gcc w_src/test.c -s -o exec/test -Wall -m64 -DUNIX -L./exec -l:libw.so -l:cipher_lib.so */
|
||||
|
||||
#include "convert.h"
|
||||
#include "cipher.h"
|
||||
|
||||
env e;
|
||||
|
||||
modContextCipher ctx;
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
init_env(&e);
|
||||
//
|
||||
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);
|
||||
//str2hex(&e, &v, &w);
|
||||
str2base64(&e, &v, &w);
|
||||
printf("%s\n", w.mPtr);
|
||||
dynLet(&e, &v, "dGVzdCBkZXMgZW5jb2RhZ2VzMTI=", DYN_LGNONE);
|
||||
base642str(&e, &v, &w);
|
||||
printf("decodage: %s\n", w.mPtr);
|
||||
dynLet(&e, &v, "303132333435363738394142434445", DYN_LGNONE);
|
||||
hex2str(&e, &v, &w);
|
||||
printf("hexa2str: %s\n", w.mPtr);
|
||||
//
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
+671
@@ -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;
|
||||
}
|
||||
@@ -29,7 +29,16 @@
|
||||
#include "var.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
|
||||
// force exporting
|
||||
#ifdef WINLIB
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL __declspec(dllexport)
|
||||
#else
|
||||
#undef WAPIDECL
|
||||
#define WAPIDECL
|
||||
#endif
|
||||
|
||||
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
|
||||
{
|
||||
/* ne pas regarder le type precedent : ecraser ! */
|
||||
if(v == NULL)
|
||||
@@ -55,7 +64,7 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
|
||||
v->lg = 0;
|
||||
v->lgmax = sep_lgm;
|
||||
v->ptr[0] = 0;
|
||||
v->codePage = CP_DEFAULT;
|
||||
v->codePage = WCP_DEFAULT;
|
||||
}
|
||||
break;
|
||||
case VAR_BUFFER:
|
||||
@@ -102,23 +111,130 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
|
||||
}
|
||||
}
|
||||
|
||||
void var_ctrl_param(env * e, var * v)
|
||||
// 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)
|
||||
{
|
||||
/* controle que la var "v", si de type PARAM, pointe sur une var toujours existante... */
|
||||
if(v->type != VAR_PARAM)
|
||||
return;
|
||||
/* TODO lire e->par_ptr de type dynamic ??? */
|
||||
/* dans le cas : hash, puis var de hash, puis clear hash : quid de la var de hash : ras car c'est une copie ! */
|
||||
if(v == NULL || num == NULL)
|
||||
return FALSE;
|
||||
if(v->type == VAR_PARAM)
|
||||
{
|
||||
if((v = (var *)v->ptr) == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
if(v->type == VAR_NUMBER)
|
||||
{
|
||||
*num = v->num;
|
||||
return TRUE;
|
||||
}
|
||||
if(v->type != VAR_DYNAMIC)
|
||||
return FALSE;
|
||||
/* convertir si string, en number */
|
||||
*num = dynToNumber(e, v);
|
||||
return(v->mInternal == DYN_OK);
|
||||
}
|
||||
|
||||
void var_free(env * e, var * v, int suivre_par)
|
||||
WAPIDECL void var_free(env * e, var * v, int suivre_par)
|
||||
{
|
||||
var * pvar;
|
||||
/* */
|
||||
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)
|
||||
{
|
||||
@@ -149,17 +265,29 @@ void var_free(env * e, var * v, int suivre_par)
|
||||
v->type = VAR_NULL;
|
||||
}
|
||||
|
||||
void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
|
||||
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
|
||||
{
|
||||
var * pvar;
|
||||
/* tient compte de la valeur precedente de la var ; suivre_let/suivre_v = TRUE pour travailler avec la var pointee */
|
||||
/* 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)
|
||||
{
|
||||
@@ -173,7 +301,6 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
|
||||
case VAR_DYNAMIC:
|
||||
var_init(e, let, v->type, 0, v->lg + 1, NULL); // +1 pour le \0 de fin
|
||||
memcopie(let->ptr, v->ptr, v->lg + 1); // permet de copier le \0 de fin
|
||||
//memcpy(let->ptr, v->ptr, v->lg + 1);
|
||||
let->lg = v->lg;
|
||||
break;
|
||||
//
|
||||
@@ -183,13 +310,15 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
|
||||
// boucler et copier les elements, attention aux cycles !
|
||||
hashtable_select(e, v);
|
||||
while(hashtable_next(e, v, e->nom, &pvar))
|
||||
// TODO copie recursive + copie de la var "pvar"
|
||||
hashtable_do(e, HASH_WRITE, let, e->nom, &pvar);
|
||||
hashtable_do(e, HASH_WRITE, let, e->nom, &pvar); // WRITE appelle var_let : recursif de fait
|
||||
break;
|
||||
//
|
||||
case VAR_PARAM:
|
||||
if(!suivre_v)
|
||||
if(!suivre_v) // ??
|
||||
{
|
||||
var_init(e, let, VAR_PARAM, 0, 0, v->ptr);
|
||||
let->etat = v->etat;
|
||||
}
|
||||
break;
|
||||
|
||||
case VAR_BUFFER:
|
||||
@@ -198,4 +327,36 @@ 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 ? */
|
||||
}
|
||||
|
||||
/* ********************************************** */
|
||||
@@ -23,10 +23,17 @@
|
||||
#ifndef VAR_H
|
||||
#define VAR_H
|
||||
|
||||
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
|
||||
void var_ctrl_param(env * e, var * v);
|
||||
void var_free(env * e, var * v, int suivre_par);
|
||||
void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
|
||||
#include "apidecl.h"
|
||||
|
||||
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
|
||||
WAPIDECL int var_conv_num(env * e, var * v, number * num);
|
||||
WAPIDECL void var_free(env * e, var * v, int suivre_par);
|
||||
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
|
||||
WAPIDECL void var_resize(env * e, var * v, ent64 mod_lgm, ent64 sep);
|
||||
|
||||
WAPIDECL int varptrtbl_ctrl(env * e, var * v);
|
||||
WAPIDECL void varptrtbl_maj(env * e, var * v);
|
||||
WAPIDECL void varptrtbl_del(env * e, var * v);
|
||||
|
||||
/* ********************************************** */
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
set WBIN=exec
|
||||
set WLIB=.
|
||||
set WSRC=.
|
||||
exec\lwc prg.w
|
||||
exec\lwa prg.wa
|
||||
exec\lw prg
|
||||
rem
|
||||
exec\lwc comp.w
|
||||
exec\lwa comp.wa
|
||||
exec\lw comp
|
||||
rem
|
||||
exec\lwc pdf.w
|
||||
exec\lwa pdf.wa
|
||||
exec\lw pdf
|
||||
rem
|
||||
exec\lwc debug.w
|
||||
exec\lwa debug.wa
|
||||
exec\lw debug 1234
|
||||
@@ -51,13 +51,13 @@ input: input
|
||||
|
||||
declare: declare
|
||||
let: let
|
||||
delet: delet ; unlet ??
|
||||
delet: delet
|
||||
|
||||
new: new
|
||||
class: class
|
||||
this: this
|
||||
parent: parent
|
||||
free: free
|
||||
hold: hold
|
||||
precision: precision
|
||||
setsep: setsep
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/*************************************************************************************
|
||||
* w.php
|
||||
* -----
|
||||
* Author: FDE
|
||||
* Contributors:
|
||||
* Copyright: (c) 2023
|
||||
* Release Version: 1.0
|
||||
* Date Started: 05/10/2024
|
||||
*
|
||||
* W language file for GeSHi.
|
||||
*
|
||||
* a mettre ici : /lamp0/web/vhosts/www.lanisys.fr/htdocs/wiki/vendor/geshi/geshi/src/geshi
|
||||
*
|
||||
*************************************************************************************
|
||||
*
|
||||
* This file is part of GeSHi.
|
||||
*
|
||||
* GeSHi is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GeSHi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GeSHi; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
$language_data = array (
|
||||
'LANG_NAME' => 'W',
|
||||
'COMMENT_SINGLE' => array(1 => ';'),
|
||||
'COMMENT_MULTI' => array(),
|
||||
'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,
|
||||
'QUOTEMARKS' => array('"', '\''),
|
||||
'ESCAPE_CHAR' => '',
|
||||
'KEYWORDS' => array(
|
||||
1 => array(
|
||||
'begin', 'background', 'library', 'except', 'end', 'sub',
|
||||
'endsub', 'include', 'loop', 'endloop', 'return', 'returnon',
|
||||
'break', 'breakon', 'continue', 'continueon', 'throw', 'catch',
|
||||
'foreach', 'in', 'like', 'if', 'then', 'elseif', 'else',
|
||||
'endif', 'endfor','echo', 'echonl', 'input', 'nop', 'part', 'declare',
|
||||
'let', 'do', 'call', 'invoke', 'delet', 'class', 'free',
|
||||
'new', 'this', 'parent', 'precision', 'setsep'
|
||||
),
|
||||
2 => array(
|
||||
'or', 'and', 'not', 'int', 'frac', 'abs', 'neg', 'type', 'typeof',
|
||||
'tonum', 'tostring', 'count', 'len', 'format', 'dcount',
|
||||
'round', 'field', 'index', 'search', 'change', 'insert', 'remove'
|
||||
)
|
||||
),
|
||||
'SYMBOLS' => array(
|
||||
'(', ')', '{', '}', '[', ']'
|
||||
),
|
||||
'CASE_SENSITIVE' => array(
|
||||
GESHI_COMMENTS => false,
|
||||
1 => true,
|
||||
2 => true,
|
||||
),
|
||||
'STYLES' => array(
|
||||
'KEYWORDS' => array(
|
||||
1 => 'color: #b1b100; font-weight: bold;',
|
||||
2 => 'color: #b1b100;'
|
||||
),
|
||||
'COMMENTS' => array(
|
||||
1 => 'color: #666666; font-style: italic;',
|
||||
),
|
||||
'ESCAPE_CHAR' => array(
|
||||
0 => 'color: #000099; font-weight: bold;'
|
||||
),
|
||||
'BRACKETS' => array(
|
||||
0 => 'color: #000066;'
|
||||
),
|
||||
'STRINGS' => array(
|
||||
0 => 'color: #009900;'
|
||||
),
|
||||
'NUMBERS' => array(
|
||||
0 => 'color: #CC0000;'
|
||||
),
|
||||
'METHODS' => array(
|
||||
1 => 'color: #006600;'
|
||||
),
|
||||
'SYMBOLS' => array(
|
||||
0 => 'color: #000066;'
|
||||
),
|
||||
'REGEXPS' => array(
|
||||
),
|
||||
'SCRIPT' => array(
|
||||
0 => '',
|
||||
1 => '',
|
||||
)
|
||||
),
|
||||
'URLS' => array(
|
||||
1 => '',
|
||||
2 => ''
|
||||
),
|
||||
'OOLANG' => false,
|
||||
'OBJECT_SPLITTERS' => array(
|
||||
1 => '\\'
|
||||
),
|
||||
'REGEXPS' => array(
|
||||
),
|
||||
'STRICT_MODE_APPLIES' => GESHI_NEVER,
|
||||
'SCRIPT_DELIMITERS' => array(),
|
||||
'HIGHLIGHT_STRICT_BLOCK' => array(
|
||||
0 => false,
|
||||
1 => false
|
||||
)
|
||||
);
|
||||
+91
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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,free,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
|
||||
@@ -43,7 +43,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
|
||||
1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73
|
||||
1,1,74;1,1,68;1,1,69;1,1,73
|
||||
1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74
|
||||
1,1,66;1,1,72;1,1,65;1,1,65
|
||||
1,1,68;1,1,6F;1,1,6C;1,1,64
|
||||
1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E
|
||||
1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70
|
||||
1,1,69;1,1,6E;1,1,74
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user