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

Signed-off-by: Deville <nicolas@lanisys.fr>
2026-08-09 20:17:28 +02:00
fred 97065a4e47 fix: lex bug (hard-coded token number) + xml.w 2026-08-09 19:00:43 +02:00
fred 4ed586d2dc feat: named parameters invoking C modules
feat: lex with state management
2026-08-07 17:30:57 +02:00
fred a20c4733ad WIP named parameters invoking C modules + code cleaning 2026-08-02 18:26:50 +02:00
fred ecb07de56e WIP named parameters 2026-08-01 21:02:46 +02:00
fred 9b04cf31ac Merge branch 'dev/alpha-9' of https://git.lanisys.fr/lanisys/W into dev/alpha-9
# Conflicts:
#	pdf_lib.c
2026-08-01 18:49:19 +02:00
fred 6f88a95edd feat: named parametres
feat: cipher AES 128/192/256 bits
feat: pfdMod enables dynamic number of pages + barcode ean128
WIP: named parameters when invoking C module
2026-08-01 18:42:38 +02:00
Lanisys 48719bc369 feat: pdfMod with unknown page number & CAB EAN128 2026-07-26 17:29:44 +02:00
Lanisys 4e7ba72eda fix: readme 2026-07-19 16:14:03 +02:00
Lanisys 726df4dcb9 fix: review readme 2026-07-19 16:12:19 +02:00
fred b6bea78591 feat: release alpha-8 2026-07-14 10:19:52 +02:00
fred 0445f10ebe WIP VAR_PARAM management 2026-06-28 18:01:09 +02:00
fred ad317a2070 feat: ssh_lib, VAR_PARAM management (when hashtable element) 2026-06-28 16:12:04 +02:00
fred e0eaf6f9e8 WIP exception bubbling 2026-06-14 18:14:25 +02:00
fred b70cee802b WIP exception bubbling
WIP ssh lib
2026-06-14 15:45:35 +02:00
63 changed files with 7094 additions and 3475 deletions

No files matched your search

+67 -40
View File
@@ -6,7 +6,7 @@ W
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -24,32 +24,7 @@ W
along with this program. If not, see <https://www.gnu.org/licenses/>.
```
# Execution
var pour la shared lib, puis exécution :
```
export LD_LIBRARY_PATH=/home/fde/dev/langage/w/exec
(sur le serveur de dev. pour que ce soit compatible avec la version installee)
sudo ln -s /home/fde/dev/langage/w/lex /etc/wlanguage
exec/lw -t -WBIN:./exec -WSRC:. test
```
# Infos
voir les modules en memoire :
```
ldd
objdump/readelf (moins bien)
cat /proc/*/maps et faire des grep pour voir les .so et module chargés par opendl
```
# Compilation et execution
```
# exec/lwc $1.w $1.wa < $1.w ; exec/lwa $1.wa ; exec/lw $1
exec/genw $1.w && exec/lwa $1.wa && rm $1.wa && exec/lw $1
```
# Site Web
https://w.lanisys.fr/
# French
## LANGAGE W
@@ -59,19 +34,10 @@ Le but du langage W est d’être simple, efficace, robuste.
Il est fourni avec un compilateur qui génère un code binaire de type
*p-code*, compatible toute plateforme.
Un exécuteur de p-code W sera disponible sur Linux et d’autres OS.
Un interpréteur W permet également d’exécuter un programme W en mode
*script*.
Un module FastCGI permettra de plus d’utiliser le langage W en mode
interprété ou compilé pour les sites Internet.
Enfin, les programmes W pourront être appelés depuis d’autres
Les programmes W pourront être appelés depuis d’autres
programmes, un peu comme un langage de plugins.
Deux utilitaires permettent de formatter le code source et de générer de
la documentation à partir de *tags* dans le code, au format
[DokuWiki](https://www.dokuwiki.org/dokuwiki).
Description du fonctionnement des [programmes](/w/prog) d’exécution et
compilation.
L'utilitaire *lwf* permettent de formatter le code source.
Pour démarrer, premier programme d’exemple :
``` w
@@ -82,4 +48,65 @@ except
end
```
Voici la description complète du [langage W](/w/instr).
# Installation
Installation depuis les dépôts officiels pour base Debian/Ubuntu:
```
sudo apt update
sudo apt install ca-certificates curl
sudo curl -fsSL http://apt.lanisys.fr/public.key -o /etc/apt/keyrings/wlanguage.gpg
sudo tee /etc/apt/sources.list.d/wlanguage.sources <<EOF
Types: deb
URIs: http://apt.lanisys.fr
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: main
Signed-By: /etc/apt/keyrings/wlanguage.gpg
EOF
sudo apt update
sudo apt install wlanguage
sudo exec bash -l
```
Voici la description complète du [langage W](https://w.lanisys.fr/doku.php?id=reference).
# English
## W LANGUAGE
### Overview
The goal of the W language is to be simple, efficient, and robust.
It comes with a compiler that generates *p-code* binary code,
compatible with any platform.
A W p-code executor will be available for Linux and other operating systems.
W programs will be callable from other programs, much like a plugin system.
The *lwf* utility is available for formatting source code.
To get started, here is a first example program:
``` w
; The famous Hello World in W
begin hello
echonl "Hello world !"
except
end
```
# Installation
Installation from the official repositories for Debian/Ubuntu-based systems:
```
sudo apt update
sudo apt install ca-certificates curl
sudo curl -fsSL http://apt.lanisys.fr/public.key -o /etc/apt/keyrings/wlanguage.gpg
sudo tee /etc/apt/sources.list.d/wlanguage.sources <<EOF
Types: deb
URIs: http://apt.lanisys.fr
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: main
Signed-By: /etc/apt/keyrings/wlanguage.gpg
EOF
sudo apt update
sudo apt install wlanguage
sudo exec bash -l
```
Here is the complete description of the [W language](https://w.lanisys.fr/doku.php?id=reference).
+7 -4
View File
@@ -1,8 +1,9 @@
#define ARG_DEBUG "d"
#define ARG_TRACE "t"
#define ARG_DISASM "u"
#define ARG_COMPRESS "c"
#define ARG_DEBUG "d" /* avec lw */
#define ARG_TRACE "t" /* avec lw */
#define ARG_DISASM "u" /* avec lwa */
#define ARG_COMPRESS "c" /* avec lwa */
#define ARG_SOURCE "s" /* avec lwc */
void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
{
@@ -21,6 +22,8 @@ void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
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)
+14 -7
View File
@@ -414,10 +414,12 @@ int assembler(env * e, char * fichier, int * cptLig, int compress)
case IN_SELE:
case IN_RNXT:
case IN_CPHA:
case IN_CPHH:
// PVAT / TYPO / PSHT / SELE / RNXT / CPHA
PCODE(instr);
break;
case IN_CPSH:
case IN_CPAN:
case IN_CPHN:
case IN_PARM:
case IN_PVAR:
case IN_PVAH:
@@ -435,7 +437,7 @@ int assembler(env * e, char * fichier, int * cptLig, int compress)
case IN_NLET:
case IN_PVHD:
case IN_PVID:
// CPSH / PARM / PVAR / PVAH / PVAI / DELE / NLET / PHDE / PIDE
// CPAN / CPHN / PARM / PVAR / PVAH / PVAI / DELE / NLET / PHDE / PIDE
//dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
//num = dynToNum(e, &tmp, 0, 3) & 255;
//if(tmp.mInternal == DYN_ERR) { ret = -3; break; } // erreur conversion
@@ -669,7 +671,9 @@ int assembler(env * e, char * fichier, int * cptLig, int compress)
PCODE(tmp.mPtr[p]);
break;
case IN_INCL:
// INCL (lg=0 possible si rien)
// INCL (lg=0 possible si rien) - ne pas mettre dans le pcode car ne sert plus
i++;
break;
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 0 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
@@ -923,7 +927,8 @@ int disassembler(env * e, char * fichier)
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_CPSH:
case IN_CPAN:
case IN_CPHN:
case IN_PARM:
case IN_PVAR:
case IN_PVAH:
@@ -942,8 +947,8 @@ int disassembler(env * e, char * fichier)
case IN_PVHD:
case IN_PVID:
case IN_PNAM:
case IN_INCL:
// CPSH / PARM / PVAR / PVAH / PVAI / DELE / NLET / PNAM / INCL / PHDE / PIDE
//case IN_INCL:
// CPAN / CPHN / PARM / PVAR / PVAH / PVAI / DELE / NLET / PNAM / INCL / PHDE / PIDE
si++;
lg = pcode.ptr[si++];
for(int p = 0; p < lg; p++)
@@ -1086,6 +1091,8 @@ int disassembler(env * e, char * fichier)
// RNXT
case IN_CPHA:
// CPHA
case IN_CPHH:
// CPHJ
case IN_PSHV:
// PSHV
case IN_POPV:
@@ -1227,7 +1234,7 @@ int main(int argc, char * argv[])
/* avis de licence */
printf("W language Copyright 2024,2025 lanisys.fr\n");
printf("This program comes with ABSOLUTELY NO WARRANTY;\nThis is free software, and you are welcome to redistribute it\nunder certain conditions (GPL-3.0-or-later)\n\n");
/* argument : fichier a assembler/desassembler (si -d), assembler avec compression lzw (si -c) */
/* argument : fichier a assembler/desassembler (si -u), assembler avec compression lzw (si -c) */
if(argc < 2)
{
printf("Usage: lwa [-c|-u] [-WLIB:<chemin>] <fichier.wa|fichier.wp>\n");
+169 -63
View File
@@ -27,7 +27,9 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "cipher.h"
typedef struct {
@@ -35,16 +37,21 @@ typedef struct {
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
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
/* *********************************************************************************** */
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
@@ -54,114 +61,213 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// MD2(entree, resultat)
// MD4(entree, resultat)
//
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
cipherInit(e, &p_etat->ctxMod);
// 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))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
cipherEnd(e, &p_etat->ctxMod);
//printf("mod end %d\n", p_etat->test);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODETAT;
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 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
// 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;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1 == NULL)
exc = EX_MODETAT;
else if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toAES128", 8))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
else if(paramKey->type != VAR_DYNAMIC || paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
setError(p_etat, cipher_AES128(e, &p_etat->ctxMod, param1, param2, param3)); /* param1 = key, param2 = input, param3 = output */
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))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
else if(paramKey->type != VAR_DYNAMIC || paramEncrypted->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
setError(p_etat, decipher_AES128(e, &p_etat->ctxMod, param1, param2, param3)); /* param1 = key, param2 = input, param3 = output */
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
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+4
View File
@@ -27,6 +27,10 @@ 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
+4
View File
@@ -58,6 +58,10 @@ 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
+109 -67
View File
@@ -27,7 +27,9 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "convert.h"
typedef struct {
@@ -35,16 +37,22 @@ typedef struct {
//*** 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_CONVFMT 1
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"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -55,135 +63,169 @@ 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
//
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toHexa", 6))
{
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(str2hex(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
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))
{
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramHexadecimal->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(hex2str(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
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))
{
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(str2base64(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
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))
{
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramBase64encoded->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(base642str(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
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
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+4 -14
View File
@@ -64,26 +64,16 @@ char * strerr[] = {
"EX_SORTEDSEARCH_KO sort type incorrect",
"EX_SQRT_NEG square root of a negative number is not calculated.",
"EX_INT_EXP Fractional exponentiation is not calculated",
"EX_VARPARAM_KO Null parameter pointer"
"EX_VARPARAM_KO Null parameter pointer",
"EX_PARAM_NOTFOUND Named parameter not found", // 45
"EX_NUMOVF Numeric overflow",
"EX_INPUT_TTY Cannot read from terminal or stdin"
};
enum {
cLF = 10
};
long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, cLF);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, cLF, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
/*
blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,identnext,8,reste,9
*/
+22
View File
@@ -321,6 +321,28 @@ WAPIDECL long dynCtrl(env * e, Dynamic * this, long lg, long copier)
return DYN_OK;
}
WAPIDECL long dynResize(env * e, Dynamic * this, long lgmax)
{
if(this->mPtr == NULL)
return DYN_ERR;
if(lgmax < DYN_LGMIN)
lgmax = DYN_LGMIN;
if(this->mLgmax != lgmax)
{
char * tmp = (char *)memalloc(e, lgmax);
if(tmp == NULL)
return DYN_ERR;
memfree(e, this->mPtr);
this->mLgmax = lgmax;
this->mPtr = tmp;
}
/* raz dynamic */
this->mLg = 0;
this->mPtr[0] = 0;
this->mInternal = 0;
return DYN_OK;
}
WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg)
{
/* UTF8 lg physique ici */
+1
View File
@@ -85,6 +85,7 @@ WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg);
WAPIDECL long dynLengthUtf8(const char * p, long lg, int separator);
WAPIDECL long dynNextUtf8(char ** p, long lg, long * pos, char * carU8, int separator);
WAPIDECL long dynCtrl(env * e, Dynamic * this, long lg, long copier);
WAPIDECL long dynResize(env * e, Dynamic * this, long lgmax);
WAPIDECL long Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL long UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
+155 -110
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -25,6 +25,11 @@
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
@@ -32,28 +37,35 @@
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
#include "dynamic.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_RENAME 1
#define EXMOD_REMOVE 2
#define EXMOD_READ 3
#define EXMOD_WRITE 4
#define EXMOD_ACCESS 5 /* open seek */
enum {
EXMOD_RENAME = 1,
EXMOD_REMOVE = 2,
EXMOD_READ = 3,
EXMOD_WRITE = 4,
EXMOD_ACCESS = 5, /* open seek */
EXMOD_NB = 5
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Rename error",
"Delete error",
"Read error",
"Write error",
"Access error while opening/seeking" // 5
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -62,137 +74,150 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// les differentes fonctions : file.create/open/close/read/write/get/set/size/dir
// ( init/end/vers/error sont obligatoires pour tout module )
// create : creer un fichier ; flag overwrite = false : exception si existe, si flag = true, raz du fichier existant TODO
// open : ouvre un fichier existant, exception si inexistant TODO
// close : fermeture du fichier TODO
// read : lecture du fichier TODO
// write : ecriture du fichier TODO
// - - - - - - - - - - - - - - - - - - - -
// get : recupere dans param un dynamic contenant le fichier
// set : ecrit depuis param le dynamic dans le fichier (param = nom FM contenu)
// size : donne la taille sur disque du fichier
// dir : donne la liste des fichiers et repertoires d'un repertoire
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
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 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "rename", 6))
{
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;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramOldPath->type != VAR_DYNAMIC || paramNewPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(rename(param1->mPtr, param2->mPtr))
if(rename(paramOldPath->mPtr, paramNewPath->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "delete", 6))
{
if(param1 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
if(paramPath == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(remove(param1->mPtr))
if(remove(paramPath->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "append", 6))
{
if(param1 == NULL || param2 == NULL)
/* 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;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FILE * fic;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "ab")) == 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, "a")) == NULL) /* mode "a" creer le fichier s'il n'existe pas (Unix et Windows) */
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, EXMOD_ACCESS);
else
{
if(fseek(fic, 0, SEEK_END) != 0)
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 !! */
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);
}
@@ -201,37 +226,45 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* utilisation de dynRead qui fait le travail, param1 : nom, param2 : contenu lu */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramContent = getParam(e, "content", 7);
/* utilisation de dynRead qui fait le travail */
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynRead(e, param2, param1->mPtr) != DYN_OK)
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(param1 == NULL || param2 == NULL)
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
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, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "w")) == NULL)
if((fic = fopen(paramPath->mPtr, "w")) == NULL)
#endif
exc = setError(p_etat, EXMOD_ACCESS); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fwrite(param2->mPtr, param2->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
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);
}
@@ -240,20 +273,22 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "size", 4))
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
/* */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramLength = getParam(e, "length", 6);
if(paramPath == NULL || paramLength == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
if((fic = fopen(paramPath->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "r")) == NULL)
if((fic = fopen(paramPath->mPtr, "r")) == NULL)
#endif
exc = setError(p_etat, EXMOD_ACCESS); /* erreur generique : lire la vraie erreur ailleurs */
else
@@ -262,8 +297,10 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
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);
}
@@ -272,28 +309,33 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "dir", 3))
{
/* copie du code de dynRead, plus court */
if(param1 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramFileList = getParam(e, "fileList", 8);
if(paramPath == NULL || paramFileList == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramFileList->type != VAR_DYNAMIC)
var_let(e, paramFileList, &e->int_dynamic, FALSE, FALSE);
/* copie du code de dynRead, plus court */
#ifdef UNIX
DIR * rep = NULL;
if((rep = opendir(param1->mPtr)) == NULL)
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);
}
}
/* */
@@ -302,32 +344,35 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
dynConcatSz(e, param1, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(param1->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
dynLet(e, paramFileList, paramPath->mPtr, paramPath->mLg);
dynConcatSz(e, paramFileList, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(paramFileList->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
{
dynSetLen(e, param1, 0); // idem raz
dynSetLen(e, paramFileList, 0);
for(int cr = -1;cr != 0;)
{
if(strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
{
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, FindFileData.cFileName, DYN_LGNONE);
if(paramFileList->mLg > 0)
dynConcatSz(e, paramFileList, sFM, 1);
dynConcatSz(e, paramFileList, FindFileData.cFileName, DYN_LGNONE);
}
cr = FindNextFile(hFind, &FindFileData);
}
FindClose(hFind);
}
else
{
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;
}
+122 -38
View File
@@ -28,33 +28,22 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
#include "instr.h"
env e;
long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, 10);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, 10, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
/*
blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10
sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20
return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30
continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40
new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50
neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60
format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70
lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80
indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90
multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99
neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60
search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70
gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80
endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90
numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100
modsep,101,other,102
*/
struct {
ent16 blank,comment,begin,background,library,end,except,throw,catch,include;
@@ -62,11 +51,12 @@ struct {
ent16 return_,returnon,loop,endloop,foreach,in,like,endfor,break_,breakon;
ent16 continue_,continueon,nop,part,echonl,echo,input,declare,let,delet;
ent16 new,class,this,parent,hold,precision,setsep,int_,frac,abs;
ent16 neg,round,type,len,count,dcount,field,index,search,change;
ent16 format,insert,remove,tonum,tostring,equal,diff,gt,lt,gte;
ent16 lte,and,or,not,beginpar,endpar,beginh,endh,begins,ends;
ent16 indirect,typeof_,stringdq,stringq,ident,varsys,numberdec,numberint,minus,plus;
ent16 multiply,divide,divident,modulo,concat,listesep,identsep,modsep,other;
ent16 neg,round,sqrt,exp,type,len,count,dcount,field,index;
ent16 search,sortedsearch,change,format,insert,remove,tonum,tostring,equal,diff;
ent16 gt,lt,gte,lte,and,or,not,beginpar,endpar,beginh;
ent16 endh,begins,ends,indirect,typeof_,stringdq,stringq,ident,varsys,numberdec;
ent16 numberint,minus,plus,multiply,divide,divident,modulo,concat,listesep,identsep;
ent16 modsep,other;
} r;
void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
@@ -128,15 +118,18 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
/* */
r.neg = rg(e, regles, "neg", tmp);
r.round = rg(e, regles, "round", tmp);
r.sqrt = rg(e, regles, "sqrt", tmp);
r.exp = rg(e, regles, "exp", tmp);
r.type = rg(e, regles, "type", tmp);
r.len = rg(e, regles, "len", tmp);
r.count = rg(e, regles, "count", tmp);
r.dcount = rg(e, regles, "dcount", tmp);
r.field = rg(e, regles, "field", tmp);
r.index = rg(e, regles, "index", tmp);
r.search = rg(e, regles, "search", tmp);
r.change = rg(e, regles, "change", tmp);
/* */
r.search = rg(e, regles, "search", tmp);
r.sortedsearch = rg(e, regles, "sortedsearch", tmp);
r.change = rg(e, regles, "change", tmp);
r.format = rg(e, regles, "format", tmp);
r.insert = rg(e, regles, "insert", tmp);
r.remove = rg(e, regles, "remove", tmp);
@@ -144,10 +137,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.tostring = rg(e, regles, "tostring", tmp);
r.equal = rg(e, regles, "equal", tmp);
r.diff = rg(e, regles, "diff", tmp);
/* */
r.gt = rg(e, regles, "gt", tmp);
r.lt = rg(e, regles, "lt", tmp);
r.gte = rg(e, regles, "gte", tmp);
/* */
r.lte = rg(e, regles, "lte", tmp);
r.and = rg(e, regles, "and", tmp);
r.or = rg(e, regles, "or", tmp);
@@ -155,10 +148,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.beginpar = rg(e, regles, "beginpar", tmp);
r.endpar = rg(e, regles, "endpar", tmp);
r.beginh = rg(e, regles, "beginh", tmp);
/* */
r.endh = rg(e, regles, "endh", tmp);
r.begins = rg(e, regles, "begins", tmp);
r.ends = rg(e, regles, "ends", tmp);
/* */
r.indirect = rg(e, regles, "indirect", tmp);
r.typeof_ = rg(e, regles, "typeof", tmp);
r.stringdq = rg(e, regles, "stringdq", tmp);
@@ -166,10 +159,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.ident = rg(e, regles, "ident", tmp);
r.varsys = rg(e, regles, "varsys", tmp);
r.numberdec = rg(e, regles, "numberdec", tmp);
/* */
r.numberint = rg(e, regles, "numberint", tmp);
r.minus = rg(e, regles, "minus", tmp);
r.plus = rg(e, regles, "plus", tmp);
/* */
r.multiply = rg(e, regles, "multiply", tmp);
r.divide = rg(e, regles, "divide", tmp);
r.divident = rg(e, regles, "divident", tmp);
@@ -177,6 +170,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.concat = rg(e, regles, "concat", tmp);
r.listesep = rg(e, regles, "listesep", tmp);
r.identsep = rg(e, regles, "identsep", tmp);
/* */
r.modsep = rg(e, regles, "modsep", tmp);
r.other = rg(e, regles, "other", tmp);
}
@@ -188,17 +182,103 @@ enum {
static void formatage_asm(Dynamic * s, Dynamic * f)
{
// TODO
Dynamic trav, lig; /* variables de travail */
dynInit(&e, &trav, 0);
dynInit(&e, &lig, 0);
long sdlw = 0;
if(dynIndexSz(&e, s, "\r\n", 2, 1) > -1)
{
/* saut de ligne windows : supprimer \r et les remettre a la fin */
sdlw = 1;
/* supprimer les \r de la chaine ! */
dynErase(&e, s, "\r");
}
//
long numlig = 0, niveau = 0, flag_trt;
dynRemove(&e, s, NULL, 0, DYN_TRUE);
while(dynRemove(&e, s, &lig, 10, DYN_FALSE) > -1)
{
// traiter chaque ligne
numlig++;
if(lig.mLg == 0)
continue; // ligne vide
//
// mettre dans trav la ligne sans le debut (blanc/tab)
int i, pos = -1;
for(i = 0; i < lig.mLg; i++)
{
if(lig.mPtr[i] == 32 || lig.mPtr[i] == 9)
continue;
pos = i;
break;
}
if(pos == -1)
continue; /* ligne avec que des blancs/tabs : idem vide */
/* */
dynSubstr(&e, &lig, &trav, pos, lig.mLg - pos, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
/* recherche instr dans la liste */
int instr = -1, trouve = 0;
if(lig.mPtr[pos] == ';')
trouve = 1;
for(i = 0; i < 256 && !trouve; i++)
{
if(strncmp(libInstr + i * 4, trav.mPtr, 4) == 0)
{
// instruction <instr> trouvee
trouve = 1;
instr = i;
}
}
if(!trouve)
flag_trt = 0; // aligner sur le bloc courant, idem instruction ou commentaire
else if(instr == IN_PROG || instr == IN_LIBR || instr == IN_BACK || instr == IN_SUBR || instr == IN_PHDS || instr == IN_PIDS)
flag_trt = 1;
else if(instr == IN_ENDP || instr == IN_ENDS || instr == IN_ENDL)
flag_trt = 2;
else if(instr == IN_EXCE)
flag_trt = 3;
else
flag_trt = 0;
//
if(flag_trt == 1)
{
// niveau +1 apres
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + (niveau++) * TAB_COUNT);
}
else if(flag_trt == 2)
{
// niveau -1 avant
if(niveau > 0)
niveau--;
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + niveau * TAB_COUNT);
}
else if(flag_trt == 3)
{
// niveau -1 local sans changement
if(niveau > 0)
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + (niveau-1) * TAB_COUNT);
else
dynFmt(&e, &trav, &lig,'R', ' ', lig.mLg + niveau * TAB_COUNT);
}
else
{
// 0 : niveau courant
dynFmt(&e, &trav, &lig, 'R', ' ', lig.mLg + niveau * TAB_COUNT);
}
// changer la ligne courante avec sa version formatee
dynStoreSz(&e, f, numlig, DYN_NONE, lig.mPtr, lig.mLg, 10, DYN_NONE);
}
//
if(sdlw)
dynChange(&e, f, "\n", "\r\n", 0); /* remettre les sauts de ligne windows (0 = tous) */
//
dynFree(&e, &trav);
dynFree(&e, &lig);
}
static void formatage(Dynamic * s, Dynamic * f, int type)
static void formatage(Dynamic * s, Dynamic * f)
{
// s : source ; f : source apres formatage, type : 1 w, 2 pcode
if(type == 2)
{
formatage_asm(s, f);
return;
}
// s : source ; f : source apres formatage
//Dynamic token; /* contient les tokens suite au decodage lex d'une ligne */
ent16 tok; //,tok2,tok3; /* token lu par la macro ci-dessous "nreg" */
long n; /* indice en cours dans les token (parametre de la macro "nreg") base 1 */
@@ -418,7 +498,7 @@ int main(int argc, char * argv[])
if(strcmp(argv[1], "-w") == 0)
type = 1;
else if(strcmp(argv[1], "-wa") == 0)
type = 2; // formatage du pcode (fichier .wa) TODO
type = 2; // formatage du pcode (fichier .wa)
else
{
printf("Usage: lwf [-w|-wa] <source>\n");
@@ -436,7 +516,11 @@ int main(int argc, char * argv[])
}
else
{
formatage(&source, &formate, type);
if(type == 2)
formatage_asm(&source, &formate);
else
formatage(&source, &formate);
/* */
printf("%s\n", formate.mPtr);
if(dynWrite(&e, &formate, argv[argfic]) != OK)
{
+17 -10
View File
@@ -35,10 +35,10 @@ 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)
@@ -52,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);
@@ -110,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;
}
@@ -165,18 +169,21 @@ int main(int argc, char * argv[])
//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);
+188 -33
View File
@@ -39,6 +39,8 @@
enum {
WVERS = 1, /* version du compilateur w et donc du code compile */
PARAM_NBMAX = 8, /* nb maxi de parametres dans sub/library et lors de do/call/invoke */
//R_EXCEPT = 100000, /* permet de savoir si le except a ete fait dans le niveau de code */
TERM_ERR = 0,
@@ -103,6 +105,7 @@ Dynamic forend,forinc; /* variables pour le code asm des boucles foreach numeri
Dynamic varparam; /* contient les variables passees en parametre a une sub : interdire ceratins formes d'appel pour eviter plus tard des erreurs de pointeur */
int doVarParam; /* booleen pour activer dans variable() la memo des variables dans varparam */
int derPvah; /* dans un passage de parametre, indique si la derniere operation PVAR/PVAH/PVAI est bien PVAH */
int typeof_; /* gestion du cas "typeof var" dans terme() */
@@ -171,20 +174,6 @@ void fin(env * e)
dynFree(e, &varparam);
}
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
@@ -352,6 +341,21 @@ long tok2number(env * e, ent64s * numb, Dynamic * valex, Dynamic * tmp, Dynamic
}
}
long tok2negnumber(env * e, ent64s * numb, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
{
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
hex2str(e, tmp, encours);
*numb = - dynToNumber(e, encours); // negatif ici
if(encours->mInternal != DYN_OK)
return TERM_ERR; /* TODO erreur de conversion numerique */
else
{
/* reconvertir en chaine dans <encours>, au bon format */
dynLet(e, encours, Int64ToSz(e, *numb, TRUE, 0), DYN_LGNONE);
return TERM_NUM;
}
}
long tok2string(env * e, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
{
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
@@ -458,10 +462,14 @@ long variable(env * e, Dynamic * resultat, Dynamic * valex, Dynamic * tmp, Dynam
else
{
if(tok == r.identsep)
{
dynConcatSz(e, resultat, "PVAH ", 5);
derPvah = 1;
}
else
{
dynConcatSz(e, resultat, "PVAI ", 5);
derPvah = 0;
if(doVarParam)
doVarParam = 2; // indique au moins une indirection dans les vars
}
@@ -528,6 +536,16 @@ long terme(env * e, ent16 t, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
tok = nreg(n);
return ret; /* encours contient le number */
}
/* ne marche pas sur des expressions du type : let x = x - 1 */
//if(t == r.minus && (nreg(n+1) == r.numberint || nreg(n+1) == r.numberdec))
//{
// n++;
// ent64s numb;
// ret = tok2negnumber(e, &numb, valex, tmp, encours); /* token "n" */
// n++;
// tok = nreg(n);
// return ret; /* encours contient le number */
//}
if(t == r.stringq || t == r.stringdq)
{
ret = tok2string(e, valex, tmp, encours); /* token "n" */
@@ -1252,6 +1270,8 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
printf("Erreur ligne %dc%s : code trouve apres la fin du programme\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
if(trav.mLg > 0)
dynConcat(e, resultat, &trav); /* edition ligne de source dans le code assembleur wa (mis en commentaire) */
/* -------------------------------------------------------------------------------------- */
if(numNiv == 0)
{
@@ -1319,11 +1339,18 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynConcat(e, resultat, &srcdbg); // FDE A tester TODO 02/08/2025
dynConcatSz(e, resultat, "\n", 1);
/* chercher une liste de variables = liste de parametres ; que des IDENT autorises ici ! */
int nbvp = 0;
for(;tok3 != r.endpar;n += 2) /* ne rien faire si pas de parametre */
{
tok3 = nreg(n+1);
if(nreg(n) == r.ident && (tok3 == r.listesep || tok3 == r.endpar))
{
if(++nbvp > PARAM_NBMAX)
{
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : nb param library depasse le nombre maximum autorise %d\n", numlig, tmp->mPtr, PARAM_NBMAX);
return DYN_ERR; /* TODO numeroter les erreurs */
}
dynConcatSz(e, resultat, "PARM ", DYN_LGNONE);
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
hex2str(e, tmp, encours); /* la longueur d'un ident (24 max) est controlee dans lex */
@@ -1498,7 +1525,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
ent64s numb;
if(tok2number(e, &numb, valex, tmp, encours) != TERM_NUM)
{
/* TODO : tester une variable + modif langage.c/assembler */
/* TODO : tester avec variable() idem r.do + modif langage.c/assembler */
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : numero exception throw incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
@@ -1584,7 +1611,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
ent64s numb;
if(tok2number(e, &numb, valex, tmp, encours) != TERM_NUM)
{
/* TODO : tester une variable + modif langage.c/assembler */
/* TODO : tester avec variable() idem r.do + modif langage.c/assembler */
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : numero part incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
@@ -1652,7 +1679,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
/* -------------------------------------------------------------------------------------- */
if(tok == r.foreach)
{
// TODO foreach num in 1,10,1 debut/fin/incr
// foreach num in 1,10,1 debut/fin/incr / foreach var in dynamic / foreach var in hashtable
n++;
dynSetLen(e, &trav, 0);
dynSetLen(e, &envers, 0);
@@ -1715,15 +1742,14 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
if(forend.mLg == 0)
{
dynConcat(e, resultat, &envers);
dynConcatSz(e, resultat, "SELE\n", DYN_LGNONE);
dynConcatSz(e, resultat, "SELE\n", DYN_LGNONE);
/* */
AjoutNiveau(e, "F");
dynConcat(e, resultat, &label);
dynConcatSz(e, resultat, "\n", DYN_LGNONE);
/* */
//dynConcatSz(e, resultat, "PSH0\n", DYN_LGNONE); /* a remplacer */
dynConcat(e, resultat, &trav);
dynConcatSz(e, resultat, "CPHA\n", DYN_LGNONE);
dynConcatSz(e, resultat, "CRAZ\nCPHA\n", DYN_LGNONE);
dynConcat(e, resultat, &envers);
dynConcatSz(e, resultat, "RNXT\n", DYN_LGNONE);
/* */
@@ -2073,11 +2099,18 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
// ajout aux vars a controler
dynIns(e, &nivIdent, nbNivIdent, 1, encours, cFM, cVM);
n++;
int nbvp = 1;
for(;;)
{
tok = nreg(n);
tok2 = nreg(n+1);
if(tok == r.listesep && tok2 == r.ident) ; else break;
if(++nbvp > PARAM_NBMAX)
{
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : nb param sub depasse le nombre maximum autorise %d\n", numlig, tmp->mPtr, PARAM_NBMAX);
return DYN_ERR; /* TODO numeroter les erreurs */
}
n++;
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
hex2str(e, tmp, encours);
@@ -2102,10 +2135,9 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
/* -------------------------------------------------------------------------------------- */
if(tok == r.do_ || tok == r.call || tok == r.invoke)
{
//ent16 toksub = tok; // si besoin pour differencier do/call/invoke
//ent16 toksub = tok; /* pour differencier do/call/invoke */
dynSetLen(e, &envers, 0);
/* 3 formes : do var ; do ident@ident ; do library@ident
invoke ident&ident call ident */
/* 3 formes : do var ; invoke ident&ident ; call ident */
dynConcatSz(e, resultat, "SRCL ", DYN_LGNONE);
dynConcatSz(e, resultat, Int64ToSz(e, numlig, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, resultat, "\nCRAZ\n", DYN_LGNONE);
@@ -2215,11 +2247,35 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
{
dynSetLen(e, &varparam, 0);
doVarParam = 1;
int mix = 0, nbvp = 0;
/* au moins 1 var en parametre */
for(;;)
{
dynSetLen(e, &trav, 0);
aGauche = 0;
derPvah = 0;
/* verif forme : param=var + interdire le mix avec/sans param nommé */
tok2 = nreg(n); /* ne pas utiliser tok car est lu dans variable() */
tok3 = nreg(n+1);
if(tok2 == r.ident && tok3 == r.equal) // && toksub != r.invoke)
{
mix |= 1; /* parametre nomme, mix interdit avec ceux non nommes */
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
hex2str(e, tmp, &dercode); /* dercode n'est pas utilise par variable() ! */
n += 2;
}
else
{
mix |= 2; /* parametre non nommee : gestion via l'ordre, mix interdit avec nomme */
}
if(mix == 3) /* mettre mix != 1 a la place, pour ne plus autoriser les parametres non nommes */
{
/* mix parametres nommes et non nommes interdit */
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : mix parametre nommes/non-nommes do/call interdit\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
if(variable(e, &trav, valex, tmp, encours, &aGauche) == VAR_ERR)
{
doVarParam = 0;
@@ -2227,7 +2283,26 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
printf("Erreur ligne %dc%s : parametre do/call/invoke incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
dynConcatSz(e, &trav, "CPHA", DYN_LGNONE);
if(++nbvp > PARAM_NBMAX)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : nb parametre do/call/invoke superieur au maximum autorise %d\n", numlig, tmp->mPtr, PARAM_NBMAX);
return DYN_ERR; /* TODO numeroter les erreurs */
}
if(derPvah)
{
int np = dynDcount(e, &trav, '\n', DYN_NONE, DYN_NONE);
if(np >= 3)
dynInsSz(e, &trav, np - 1, DYN_NONE, "SADV", 4, '\n', DYN_NONE);
}
if(mix == 1)
{
dynConcatSz(e, &trav, derPvah ? "CPAN " : "CPHN ", DYN_LGNONE); /* parametre nomme */
dynConcat(e, &trav, &dercode);
}
else
dynConcatSz(e, &trav, derPvah ? "CPHH" : "CPHA", DYN_LGNONE); /* parametre non nomme */
dynIns(e, &envers, 1, DYN_NONE, &trav, '\n', DYN_NONE);
if(tok == r.endpar)
break;
@@ -2240,8 +2315,8 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
}
n++;
}
/* TODO => controler certaines formes de variables passees en parametre (varparam) :
(a, a) (a, a.b) (a.b, a.b.c) (a!c) : sont interdites
/* => controler certaines formes de variables passees en parametre (varparam) :
(a, a) (a, a.b) (a.b, a.b.c) (a!c) : sont interdites
*/
if(doVarParam == 2)
{
@@ -2578,7 +2653,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynConcat(e, resultat, &envers);
if(setfld == 0)
{
// TODO var[] DESV DESH DESI
// var[] DESV DESH DESI
if(aGauche != 2)
dynConcatSz(e, resultat, "DESV\n", 5); // une seule var a gauche DESV
else
@@ -2592,7 +2667,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
}
else
{
// TODO var{}[] DEZV DEZH DEZI
// var{}[] DEZV DEZH DEZI
if(aGauche != 2)
dynConcatSz(e, resultat, "DEZV\n", 5); // une seule var a gauche DEZV
else
@@ -2922,6 +2997,60 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
return DYN_ERR;
}
void source_include_tree(env * e, Dynamic * meta, Dynamic * resultat, Dynamic * tmp)
{
/*
(global) (local) (filename)
; 1 >1 fichier: 1
; 20 | >19 include: 2
; 30 | | >10 include2: 3
; 40 | | <11 2
; 42 | <20 1
; 44 | >21 include3: 2
; 50 | <23 1
; 60
*/
dynConcatSz(e, resultat, "; ----------------------------------------------\n", DYN_LGNONE);
long precLevel = 0;
long cpt, nb = dynDcount(e, meta, cVM, META_GLOBAL_LN, cFM);
for(cpt = 1; cpt <= nb; cpt++)
{
long numGlobal = dynFieldAsNumber(e, meta, META_GLOBAL_LN, cpt, cFM, cVM);
long numLocal = dynFieldAsNumber(e, meta, META_LOCAL_LN, cpt, cFM, cVM);
long level = dynFieldAsNumber(e, meta, META_LEVEL, cpt, cFM, cVM);
/* */
dynFmtNumber(e, numGlobal, tmp, 'R', ' ', 8);
dynConcatSz(e, resultat, "; ", 2);
dynConcat(e, resultat, tmp);
dynConcatSz(e, resultat, " ", 2);
/* */
dynField(e, meta, tmp, META_FILENAME, cpt, cFM, cVM, 1);
/* */
for(long i = 1; i < level; i++)
dynConcatSz(e, resultat, "| ", 7);
if(precLevel < level)
{
dynConcatSz(e, resultat, ">", 1);
dynConcatSz(e, resultat, Int64ToSz(e, numLocal, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, resultat, " ", 1);
dynConcat(e, resultat, tmp);
dynConcatSz(e, resultat, ":\n", 2);
}
else
{
dynConcatSz(e, resultat, "<", 1);
dynConcatSz(e, resultat, Int64ToSz(e, numLocal, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, resultat, "\n", 1);
}
/* */
precLevel = level;
}
/* FmtNumber(e, numlig, tmp, 'R', ' ', 8); // nb total de lignes, tous fichiers include confondus
dynConcatSz(e, resultat, "; ", 2);
dynConcat(e, resultat, tmp); */
dynConcatSz(e, resultat, "; ----------------------------------------------\n", DYN_LGNONE);
}
/* ***************************************************************************************************** */
int main(int argc, char * argv[])
@@ -2964,6 +3093,7 @@ int main(int argc, char * argv[])
dynExtractField(&e, &arg, 4, &wsrc);
dynExtractField(&e, &arg, 5, &wlib);
dynExtractSubField(&e, &arg, 2, 1, &file); // file = fichier.w a compiler
int arg_source = dynLocateSz(&e, &arg, ARG_SOURCE, cVM, 1, cFM); /* TRUE si option pour ajouter le source w dans le code assembleur genere */
/* */
for(;;)
{
@@ -3010,6 +3140,8 @@ int main(int argc, char * argv[])
if(wsrc.mPtr[wsrc.mLg - 1] != e.path_sep[0])
dynConcatSz(&e, &wsrc, e.path_sep, 1); // ajoute le / si absent a la fin
dynStore(&e, &srcdbg, META_WSRC, DYN_NONE, &wsrc, cFM, DYN_NONE);
if(arg_source)
source_include_tree(&e, &srcdbg, &resultat, &tmp);
//
if(lire_regles_lex(&e, &regles, "wlex") != DYN_OK)
{
@@ -3020,13 +3152,31 @@ int main(int argc, char * argv[])
init_reg(&e, &regles, &tmp);
/* ----------------------------------------------------------------------------------------------- */
/* resultat contient l'assembleur wa du source en entree */
char cLF = 10;
nb = 0; /* nb lignes en cours de compilation par pas de 20 lignes */
printf("Compiling.");
long currentLevel = 1, level = 0;
nbNivIdent = 0;
dynRemove(&e, &source, NULL, 0, DYN_TRUE);
while(dynRemove(&e, &source, &ligne, 10, DYN_FALSE) > -1 && ret == 0)
while(dynRemove(&e, &source, &ligne, cLF, DYN_FALSE) > -1 && ret == 0)
{
lex(&e, &regles, &ligne, &valex);
/* */
dynSetLen(&e, &trav, 0);
if(arg_source)
{
long localnumlig;
GetFile(&e, numlig + 1, &srcdbg, 1, &tmp, &localnumlig);
/* ; <file>:<numlig_local> | <source> */
dynConcatSz(&e, &trav, "; ", 2);
dynConcat(&e, &trav, &tmp);
dynConcatSz(&e, &trav, ":", 1);
dynConcatSz(&e, &trav, Int64ToSz(&e, localnumlig, FALSE, 8), DYN_LGNONE);
dynConcatSz(&e, &trav, " | ", 3);
dynConcat(&e, &trav, &ligne);
dynConcatSz(&e, &trav, "\n", 1);
}
/* */
ret = parse(&e, &valex, &resultat, &tmp, &encours, &file);
/* */
if(ret == 0)
@@ -3042,16 +3192,21 @@ int main(int argc, char * argv[])
dynConcatSz(&e, &resultat, "INCL\n", 5); /* juste informatif, en lisant le compile ; la gestion passe par _srcdbg */
currentLevel = level;
}
if(++nb > 20)
{
nb = 0;
printf(".");
}
}
/* */
if(ret == 0 && numNiv > -1) /* mettre l'erreur que si pas d'autre erreur avant */
{
ret = -5;
printf("Fin de code source inattendue\n");
printf("\nFin de code source inattendue\n");
}
if(ret == 0)
{
printf("Result : OK, lines=%d\n", numlig);
printf("\nResult : OK, lines=%d\n", numlig);
/* */
if(wlib.mPtr[wlib.mLg - 1] != e.path_sep[0])
dynConcatSz(&e, &wlib, e.path_sep, 1);
@@ -3061,8 +3216,8 @@ int main(int argc, char * argv[])
}
else
{
dynField(&e, &source, &ligne, numlig, DYN_NONE, 10, DYN_NONE, 1);
printf("Result : error %d line %d => %s\n", ret, numlig, ligne.mPtr);
dynField(&e, &source, &ligne, numlig, DYN_NONE, cLF, DYN_NONE, 1);
printf("\nResult : error %d line %d => %s\n", ret, numlig, ligne.mPtr);
}
break;
}
+11
View File
@@ -84,6 +84,17 @@ WAPIDECL char * raz_nom(env * e)
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
+1
View File
@@ -29,6 +29,7 @@ WAPIDECL void init_env(env * e);
WAPIDECL char * copy_nom(env * e, const char * s);
WAPIDECL char * raz_nom(env * e);
WAPIDECL int nom_is(env * e, const char * s);
WAPIDECL int modFnIs(env * e, const char * fn, int lg);
/* ************************************************************************** */
+2
View File
@@ -30,3 +30,5 @@ 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);
+122 -82
View File
@@ -25,21 +25,11 @@
#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 {
@@ -47,17 +37,21 @@ typedef struct {
//*** 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 err == OK ? OK : EX_MODERR;
}
#include "mod.c"
/* *********************************************************************************** */
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
@@ -67,138 +61,184 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// MD2(entree, resultat)
// MD4(entree, resultat)
//
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODETAT;
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 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
// 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;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1 == NULL)
exc = EX_MODETAT;
else if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "MD2", 3))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD2(e, param1, param2);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD2(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD4", 3))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD4(e, param1, param2);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD4(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD5", 3))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD5(e, param1, param2);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD5(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "Sha1", 4))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageSha1(e, param1, param2);
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;
}
+22
View File
@@ -693,3 +693,25 @@ WAPIDECL void encodageSha1(env * ctx, var * entree, var * sortie)
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);
}
+156 -6
View File
@@ -39,13 +39,52 @@
#endif
// =============== PRIVATE ========================================================================
static ent64 fmix64(ent64 h)
{
h ^= h >> 33;
h *= 0xff51afd7ed558ccdull;
h ^= h >> 33;
h *= 0xc4ceb9fe1a85ec53ull;
h ^= h >> 33;
return h;
}
static entry * calc_entry(char * val, var * varht)
{
/* fonctionne avec des noms de 24 octets max (val) */
ent64 hash;
/* algo de D. B e r n s t e i n / M u r m u r h a s h 6 4 */
/* autre algo */
if(0)
{
ent64 * p = (ent64 *)val;
ent64 h = 0x9e3779b97f4a7c15ull;
hash = h;
hash ^= *p++;
hash *= h;
hash ^= *p++;
hash *= h;
hash ^= *p;
hash *= h;
/* SplitMix64 */
hash ^= hash >> 30;
hash *= 0xbf58476d1ce4e5b9ull;
hash ^= hash >> 27;
hash *= 0x94d049bb133111ebull;
hash ^= hash >> 31;
}
/* */
if(0)
{
ent64 * p = (ent64 *)val;
ent64 h = 0x9e3779b97f4a7c15ull;
hash = h;
hash ^= fmix64((*p++) + h);
hash ^= fmix64((*p++) + 0x517cc1b727220a95ull);
hash ^= fmix64((*p) + 0x6eed0e9da4d94a4full);
// si longueur connue : mettre en plus la ligne suivante
//hash ^= fmix64(len * 0x9e3779b97f4a7c15ull);
hash = fmix64(hash);
}
/* */
if(0) {
ent64 * p = (ent64 *)val;
ent64 k = *p++;
@@ -70,12 +109,12 @@ static entry * calc_entry(char * val, var * varht)
hash ^= k;
hash *= m;
}
/* */
/* algo de D. B e r n s t e i n / M u r m u r h a s h 6 4 */
if(1) {
hash = 5381;
for(int iCle = 0; iCle < 24; iCle++)
if(val[iCle])
hash = hash + (hash<<5) + val[iCle]; /* hash*33 */
hash = hash + (hash << 5) + val[iCle]; /* hash * 33 */
else
break; // stop au premier \0
}
@@ -140,7 +179,7 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
}
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 */
@@ -167,7 +206,7 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
{
*v = NULL;
/* renvoyer la premiere entree libre trouvee, l'entree PAS la var (si NULL, il faudra rappeler do) */
((entry *)varht->ptr)->pvar = pfree == NULL ? NULL : &pfree->content;
((entry *)varht->ptr)->pvar = (var *)pfree;
}
/* si action = 2 delete et pas trouve : RAS */
if(action == HASH_WRITE) /* write */
@@ -195,6 +234,46 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
}
}
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;
@@ -449,4 +528,75 @@ WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
printf("taille totale=%lld, occupee=%lld (taux %lld%%), nb item=%lld\n", tot, occ, occ * 100 / tot, nb);
}
WAPIDECL void hashtable_analyze(env * e, var * varht)
{
entry * pentry; /* pointe sur une entree */
entry * pchain; /* pointe sur la premiere du groupe, servant au chainage */
entry * pchain_first; /* premier bloc */
ent64 groupe; /* groupe en cours */
/* affiche le contenu d'une hashtable */
if(varht == NULL)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
if(varht == NULL)
return;
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
if(e->demon)
{
dynPrintfInt64(e, "hashtable analyze modulo=" PRINTF_MARK " separateur=", varht->modulo, 0);
dynPrintfInt64(e, PRINTF_MARK "\n", varht->separateur, 0);
}
else
printf("hashtable analyze modulo=%lld separateur=%lld\n", varht->modulo, varht->separateur);
/* */
ent64 nb_entry, occ_entry, nb_item_group, nb_group_1entry = 0, nb_empty_group = 0, nb_item = 0;
ent64 occ_entry_min = varht->separateur/sizeof(entry), occ_entry_max = 0;
ent64 nb_entry_min = (ent64)(-1), nb_entry_max = 0;
ent64 nb_item_group_min = (ent64)(-1), nb_item_group_max = 0;
/* */
pchain = (entry *)varht->ptr;
for(groupe = 0; groupe < varht->modulo; groupe++)
{
nb_entry = 0;
nb_item_group = 0;
pchain_first = pchain;
do
{
nb_entry++;
occ_entry = 0;
pentry = pchain + 1; /* la premiere est toujours "occupee", utilisee en interne par la hashtable : ne pas mettre dans les stats */
while((ent64)pentry - (ent64)pchain < varht->separateur)
{
if((pentry->nom1 | pentry->nom2 | pentry->nom3 | pentry->content.type) == 0)
; /* entree libre */
else
{
occ_entry++; /* entree occupee */
nb_item_group++;
nb_item++;
}
pentry++;
}
/* */
if(occ_entry < occ_entry_min) occ_entry_min = occ_entry;
if(occ_entry > occ_entry_max) occ_entry_max = occ_entry;
/* chainage */
} while ((pchain = (entry *)pchain->chainage_avant) != 0);
pchain = (entry *)((ent64)pchain_first + varht->separateur);
/* */
if(nb_entry < nb_entry_min) nb_entry_min = nb_entry;
if(nb_entry > nb_entry_max) nb_entry_max = nb_entry;
if(nb_item_group < nb_item_group_min) nb_item_group_min = nb_item_group;
if(nb_item_group > nb_item_group_max) nb_item_group_max = nb_item_group;
if(nb_item_group == 0) nb_empty_group++;
if(nb_entry == 1) nb_group_1entry++;
}
printf(" => nb bloc/group: min=%lld, max=%lld, 1bloc=%lld/%lld\n", nb_entry_min, nb_entry_max, nb_group_1entry, varht->modulo);
printf(" => occ bloc: min=%lld, max=%lld (/%lld)\n", occ_entry_min, occ_entry_max, varht->separateur/sizeof(entry) - 1);
printf(" => nb item/group: min=%lld, max=%lld, empty=%lld/%lld\n", nb_item_group_min, nb_item_group_max, nb_empty_group, varht->modulo);
printf(" => nb item total=%lld\n", nb_item);
}
/* ********************************************** */
+3
View File
@@ -32,10 +32,13 @@ WAPIDECL void hashtable_free_ovf(env *e, var * varht);
WAPIDECL void hashtable_clear(env *e, var * varht);
WAPIDECL long hashtable_count(env *e, var * varht);
WAPIDECL var * hashtable_lastitemwritten(var * varht);
WAPIDECL var * hashtable_writeinfirstfreeentry(env * e, var * varht, char * nom, var * v);
WAPIDECL void hashtable_deleteentry(env * e, var * varht, var * content);
WAPIDECL void hashtable_serialize(env * e, var * varht, var * out);
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail);
WAPIDECL void hashtable_analyze(env * e, var * varht);
/* ********************************************** */
#endif
+4 -3
View File
@@ -50,6 +50,7 @@ enum {
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,
@@ -58,10 +59,10 @@ enum {
};
WAPIDECL void Init(env * e, modCtxHttp * ctx);
WAPIDECL void End(env * e, modCtxHttp * ctx);
WAPIDECL void InitHttp(env * e, modCtxHttp * ctx);
WAPIDECL void FreeHttp(env * e, modCtxHttp * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data);
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);
+133 -59
View File
@@ -27,7 +27,9 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "http.h"
typedef struct {
@@ -36,16 +38,22 @@ typedef struct {
modCtxHttp ctxHttp;
} 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_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"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -56,100 +64,166 @@ 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
Init(e, &p_etat->ctxHttp);
//
// 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))
{
//*** code specifique ici
End(e, &p_etat->ctxHttp);
//
// liberation specifique au module avant arret process
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))
{
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, "get", 3))
else if(modFnIs(e, "getRequest", 10))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* 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;
if(param1->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
else if(paramInput->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
long cr = ExtractMessage(e, &p_etat->ctxHttp, param1);
param2->num = cr * NUM_FACTEUR;
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)
dynSetAs(e, param3, &p_etat->ctxHttp.content);
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
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+58 -31
View File
@@ -42,7 +42,7 @@
#define LEN_CRLF 2
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxHttp * ctx)
WAPIDECL void InitHttp(env * e, modCtxHttp * ctx)
{
ctx->error = 0;
ctx->state = HTTPSTATE_HEADERTOREAD;
@@ -55,7 +55,7 @@ WAPIDECL void Init(env * e, modCtxHttp * ctx)
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 End(env * e, modCtxHttp * ctx)
WAPIDECL void FreeHttp(env * e, modCtxHttp * ctx)
{
dynFree(e, &ctx->header);
dynFree(e, &ctx->content);
@@ -64,9 +64,10 @@ WAPIDECL void End(env * e, modCtxHttp * ctx)
dynFree(e, &ctx->methodList);
}
WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data)
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(;;)
@@ -82,44 +83,70 @@ WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data)
/* */
if(ctx->state == HTTPSTATE_HEADERTOREAD)
{
/* premiere ligne du protocole */
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)
/* premiere ligne du protocole : principale difference selon le type : Request-line or Status-line */
if(isRequest)
{
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)
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_GET_MISSING; /* http 0.9 GET seul autorise */
ctx->error = HTTP_METHOD_KO;
return HTTP_REQUEST_ERROR;
}
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynInsSz(e, &ctx->header, 2, 1, "HTTP/0.9", 3, cFM, cVM);
dynSetLen(e, &ctx->content, 0);
return HTTP_REQUEST_COMPLETE; /* requete terminee */
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;
}
/* */
ctx->state = HTTPSTATE_READINGHEADER;
ctx->lengthToRead = 0;
}
else
{
+2 -1
View File
@@ -66,7 +66,8 @@ void instr_unassemble(env * e, pointeur debutBin, ent64 nolig)
case IN_PNAM:
case IN_CLIB:
case IN_PVAI:
case IN_CPSH:
case IN_CPAN:
case IN_CPHN:
case IN_PHDE:
case IN_PIDE:
case IN_PHDH:
+8 -4
View File
@@ -42,13 +42,13 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"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" "SQRT" "IEXP" "CLIB" /* 50-59 */
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPSH" "RETT"
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPAN" "RETT"
"SELE" "RNXT" "CPHA" "PHDE" "PIDE" "PHDH" "PIDH" "PHDO" "PIDO" "PHDS"
"PIDS" "TYPE" "ROUN" "LENG" "COUN" "DCOF" "FIEL" "INDX" "SRCH" "CHNG"
"FMTA" "INSE" "REMV" "TONU" "TOST" "CCAT" "SSTR" "SSEP" "FLDF" "FLDS" /* 0-99 */
"DCOS" "FMTT" "FMTS" "SCHS" "INSS" "REMS" "DEXH" "DEXI" "PREC" "DESV"
"DESH" "DESI" "DEZV" "DEZH" "DEZI" "SDBG" "PHDN" "PIDN" "SADV" "VLET" /* 110-119 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "SSRC" "SSCS" "xxxx" "xxxx" "xxxx" /* 126 */
"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"
@@ -207,8 +207,8 @@ char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "F
#define IN_PSHT 66
#define IS_CRAZ "\x43"
#define IN_CRAZ 67
#define IS_CPSH "\x44"
#define IN_CPSH 68
#define IS_CPAN "\x44"
#define IN_CPAN 68
#define IS_RETT "\x45"
#define IN_RETT 69
@@ -330,6 +330,10 @@ char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "F
#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
+18 -18
View File
@@ -52,21 +52,21 @@ typedef struct
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMODJSON_MEM = 106,
EXMODJSON_DECODE_INCORRECT_CHAR = 101,
EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED = 102,
EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED = 103,
EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED = 104,
EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER = 105,
EXMODJSON_DECODE_UNTERMINATED_STRING = 107,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT = 108,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY = 109,
EXMODJSON_DECODE_UNEXPECTED_KEY = 110,
EXMODJSON_DECODE_UNEXPECTED_VALUE = 111,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT = 112,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT = 113,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY = 114,
EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON = 115
EXMODJSON_DECODE_INCORRECT_CHAR = 1,
EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED = 2,
EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED = 3,
EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED = 4,
EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER = 5,
EXMODJSON_MEM = 6,
EXMODJSON_DECODE_UNTERMINATED_STRING = 7,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT = 8,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY = 9,
EXMODJSON_DECODE_UNEXPECTED_KEY = 10,
EXMODJSON_DECODE_UNEXPECTED_VALUE = 11,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT = 12,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT = 13,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY = 14,
EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON = 15
};
/*
@@ -76,9 +76,9 @@ enum {
WAPIDECL int jsonInit(env * e, modContextJson * ctx);
WAPIDECL int jsonEnd(env * e, modContextJson * ctx);
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * json, var * cle, var * valeur);
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * cle, var * valeur, var * printable);
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * content, var * done);
/*
+125 -72
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,21 +27,47 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "json.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextJson jsonCtx;
} modEtat;
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
/* codes erreur dans dans json.h */
EXMOD_NB = 15
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Unexpected character",
"True keywoed expected",
"False keyword expected",
"Null keyword expected",
"Unpexted character while decoding number", // 5
"Memory error",
"End of string expected",
"Unexpected start object character",
"Unexpected start array character",
"Unexpected key", // 10
"Unexpected value",
"Unexpected next character",
"Unexpected end object character",
"Unexpected end array character",
"Unexpected end of json" // 15
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -50,127 +76,154 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "decode", 6))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramJsonText = getParam(e, "jsonText", 8);
var * paramExtractedKey = getParam(e, "extractedKey", 12);
var * paramExtractedValue = getParam(e, "extractedValue", 14);
if(paramJsonText == NULL || paramExtractedKey == NULL || paramExtractedValue == NULL)
exc = EX_MODPARAM;
else if(paramJsonText->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* param2 and param3 are dynamic (output) ; param1 must be a dynamic (input) */
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // bad type of parameter 1 or 2 or 3
else
// param3 = 1 for no double-quoted json (key and string value, except if <space> is present in value) ; future use
exc = setError(p_etat, jsonDecode(e, &p_etat->jsonCtx, param1, param2, param3));
if(paramExtractedKey->type != VAR_DYNAMIC)
var_let(e, paramExtractedKey, &e->int_dynamic, FALSE, FALSE);
if(paramExtractedValue->type != VAR_DYNAMIC)
var_let(e, paramExtractedValue, &e->int_dynamic, FALSE, FALSE);
exc = setError(p_etat, jsonDecode(e, &p_etat->jsonCtx, paramJsonText, paramExtractedKey, paramExtractedValue));
}
}
/* ============================================================================================= */
else if(modFnIs(e, "print", 5))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramExtractedKey = getParam(e, "extractedKey", 12);
var * paramExtractedValue = getParam(e, "extractedValue", 14);
var * paramPrettyPrint = getParam(e, "prettyPrint", 11);
if(paramExtractedKey == NULL || paramExtractedValue == NULL || paramPrettyPrint == NULL)
exc = EX_MODPARAM;
else if(paramExtractedKey->type != VAR_DYNAMIC || paramExtractedValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* param2 and param3 are dynamic (output) ; param1 must be a dynamic (input) */
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // bad type of parameter 1 or 2 or 3
else
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, param1, param2, param3));
if(paramPrettyPrint->type != VAR_DYNAMIC)
var_let(e, paramPrettyPrint, &e->int_dynamic, FALSE, FALSE);
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, paramExtractedKey, paramExtractedValue, paramPrettyPrint));
}
}
else if(modFnIs(e, "treeFetch", 9))
{
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramFetchParameters = getParam(e, "fetchParameters", 15);
var * paramDone = getParam(e, "done", 4);
if(paramFetchParameters == NULL || paramDone == NULL)
exc = EX_MODPARAM;
else if(paramFetchParameters->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
/* param1 must be a hash table (input) */
if(param1->type != VAR_HASHTABLE || param2->type != VAR_NUMBER)
exc = EX_MODPARAM; // bad type of parameter 1
else
exc = setError(p_etat, jsonTreeFetch(e, &p_etat->jsonCtx, param1, param2, param3));
if(paramDone->type != VAR_NUMBER)
var_let(e, paramDone, &e->int_number, FALSE, FALSE);
exc = setError(p_etat, jsonTreeFetch(e, &p_etat->jsonCtx, paramFetchParameters, paramDone));
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+38 -38
View File
@@ -682,76 +682,76 @@ WAPIDECL int jsonEnd(env * e, modContextJson * ctx)
return OK;
}
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * json, var * cle, var * valeur)
{
return Decode(e, ctx, param1->mPtr, param2, param3);
return Decode(e, ctx, json->mPtr, cle, valeur);
}
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * cle, var * valeur, var * printable)
{
char value[4] = " : \0", path = '/', index = '@';
//
return MakePrintable(e, ctx, param1, param2, param3, path, index, value);
return MakePrintable(e, ctx, printable, cle, valeur, path, index, value);
}
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * content, var * done)
{
// KeyList, CurrentKey, Name, Value, DecodeCle, DecodeValue; // Dynamic
// KeyField, KeyItem, KeyCount, ItemCount, Id, Parent, IdKey, ParentKey, ValuePresent; // Number
treefetch tree; // contexte specifique a chaque appel
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeCle"), &tree.DecodeCle);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeValue"), &tree.DecodeValue);
hashtable_do(e, HASH_READ, content, copy_nom(e, "DecodedKey"), &tree.DecodeCle);
hashtable_do(e, HASH_READ, content, copy_nom(e, "DecodedValue"), &tree.DecodeValue);
if(tree.DecodeCle == NULL || tree.DecodeValue == NULL)
{
param2->num = NUM_UN;
done->num = NUM_UN;
return OK; // TODO erreur
}
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyList"), &tree.KeyList);
if(tree.KeyList == NULL)
{
// init vars
var * v = &e->int_dynamic;
dynSetLen(e, &e->int_dynamic, 0);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyList"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "CurrentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Name"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Value"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyList"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "CurrentKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Name"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Value"), &v);
v = &e->int_number;
v->num = 1;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyField"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyItem"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Id"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyField"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyItem"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Id"), &v);
v->num = 0;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Parent"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Parent"), &v);
v->num = dynDcount(e, tree.DecodeCle, cVM, DYN_NONE, DYN_NONE);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyCount"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyCount"), &v);
v->num = dynDcount(e, tree.DecodeCle, cSVM, 1, cVM);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ItemCount"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "IdKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ParentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ValuePresent"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "ItemCount"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "IdKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "ParentKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "ValuePresent"), &v);
}
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CurrentKey"), &tree.CurrentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Name"), &tree.Name);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Value"), &tree.Value);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, content, copy_nom(e, "CurrentKey"), &tree.CurrentKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Name"), &tree.Name);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Value"), &tree.Value);
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyField"), &tree.KeyField);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyItem"), &tree.KeyItem);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyCount"), &tree.KeyCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ItemCount"), &tree.ItemCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Id"), &tree.Id);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Parent"), &tree.Parent);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "IdKey"), &tree.IdKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ParentKey"), &tree.ParentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ValuePresent"), &tree.ValuePresent);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyField"), &tree.KeyField);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyItem"), &tree.KeyItem);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyCount"), &tree.KeyCount);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ItemCount"), &tree.ItemCount);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Id"), &tree.Id);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Parent"), &tree.Parent);
hashtable_do(e, HASH_READ, content, copy_nom(e, "IdKey"), &tree.IdKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ParentKey"), &tree.ParentKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ValuePresent"), &tree.ValuePresent);
/* */
//hashtable_printdebug(e, param1, 1);
//hashtable_printdebug(e, content, 1);
if(GetNextTreeFetch(e, &tree)) // TRUE = pas fini
param2->num = NUM_ZERO; // var <fin>
done->num = NUM_ZERO; // var <fin>
else
param2->num = NUM_UN;
done->num = NUM_UN;
return OK;
}
+578 -391
View File
File diff suppressed because it is too large. Load diff
+18 -17
View File
@@ -48,14 +48,9 @@ typedef int ent32s;
typedef long long ent64s;
typedef unsigned short ent16;
#ifndef UNIX
typedef ent64s ent128s; // sous windows, pas de __int128 : TODO a changer pour des calculs corrects
#else
typedef __int128 ent128s; // temporaire pour les calculs intermediaires (multiplication)
#endif
#define NUM_MIN -999999999999999999ll
#define NUM_MAX 999999999999999999ll
#define ENT64_MAX 999999999999999999ull /* 18 chiffres dont 5 decimales version non signee pour calcul */
#define NUM_PI 314159ll
#define NUM_MOINSUN -100000ll
#define NUM_ZERO 0ll
@@ -69,6 +64,7 @@ typedef __int128 ent128s; // temporaire pour les calculs intermediaires
#define NUM_HUIT 800000ll
#define NUM_NEUF 900000ll
#define NUM_FACTEUR 100000ll /* facteur multiplicatif/diviseur pour virgule fixe (5 decimales ici) */
#define FACTEUR 100000 /* constante int 32 bits */
#define NUM_ENTIER 13 /* nb chiffres partie entiere maxi */
#define NUM_DECIMAL 5 /* nb de decimales maxi, mais precision max = NUM_DECIMAL - 1 (4 decimales ici) */
@@ -134,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 */
@@ -153,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) */
@@ -214,10 +210,10 @@ enum {
//
enum {
OK = 0,
EX_DIV0 = 1, /* exceptions */
EX_DIV0 = 1, /* division par zero */
EX_MEM = 2, /* memalloc ko */
EX_BUFOVF = 3, /* depassement de capacite du buffer */
EX_IO = 4,/* erreur d'entree/sortie (leture fichier...) */
EX_IO = 4, /* erreur d'entree/sortie (lecture fichier...) */
EX_END = 5, /* adresse du code hors prog/sub */
EX_LGNOM = 6, /* lg nom variable incorrecte (de 1 a 24 inclus) */
EX_TYPVAR = 7, /* type variable non attendu */
@@ -258,12 +254,14 @@ enum {
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 */
EXNB = 44 /* MEMO !!!! */
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 */
@@ -274,8 +272,6 @@ typedef struct {
octet tmp_cpt; /* nb de var tmp Dynamic, ne pas sauvegarder car dans la hash globale */
octet tmp_free; /* numero de var tmp Dynamic dispo ; si > tmp_cpt, a creer dans la hash globale */
//
var varptrtbl; /* contient les pointeurs sur les vars de type SUB/PARAM/OBJET, pour les rendre VAR_NULL si le ptr est libere */
//
var tmp_dynamic; /* comme son nom l'indique... doit etre utilise localement et sur une portee tres courte ; pas d'utilisation inter instruction */
var int_number; /* variable number interne servant aux conversions */
var int_dynamic; /* variable dynamic interne servant aux conversions */
@@ -285,8 +281,9 @@ typedef struct {
var * ad_var; /* permet de recuperer l'adresse d'une var entre 2 instructions */
var * ad_var_hash; /* dans les enchainements PVAR/PVAH-PVAI, donne l'adresse de la hash possédant la "derniere" variable */
var * ad_var_obj; /* dans une affectation let ou do sub, donne l'objet concerne si objet, pour lire les membres (hors sub) -> pour creer this */
var * ad_var_class; /* donne l'objet de la classe mere de l'objet courant, objet Base si objet de classe Base */
var * ad_var_sav; /* pour memoriser ad_var sur une affectation simple let a.b = c.d, instruction SADV / VLET / PHDV / PIDV */
var * ad_var_class; /* donne l'adresse de la var dynamic _class de l'objet ad_var_obj */
var * ad_var_sav; /* pour memoriser ad_var sur une affectation simple let a.b = c.d, instruction SADV / VLET / PHDV / PIDV / CPHH / CPHN */
var * ad_var_dele; /* memorise ad_var pour DELE */
/* */
ent64 exception; /* exception courante (di) ; 0 ok, si # 0, levee d'une exception et saut au code qui le traite, 0 a chaque debut de fonction */
ent64 except_ex; /* dans bloc except, code erreur ayant genere l'exception ; a mettre a 0 a chaque debut de methode sauf si appel depuis le bloc except ! */
@@ -352,6 +349,7 @@ typedef struct {
};
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];
/* */
@@ -398,6 +396,9 @@ enum {
#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,@exceptstr,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@cr,@lf,@tab,@number,@dynamic,@empty,@trim,@left,@right,@center,@surround,@asc,@desc;1,2,3,4,5,6,7,8,10,11,12,13,14,15,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,50,51,52,53,54,55,56"
#include "global.h"
+307 -207
View File
@@ -30,19 +30,26 @@ 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 !
@@ -66,207 +73,248 @@ reste: (1,1,#00-#FF) ;11; 1,1,00-FF
#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 {
long blanc, nomregle, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
ent16 blanc, nomregle, etat, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} rlex;
static long rg_lex(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
/*static void debug_valex(env * e, Dynamic * valex, Dynamic * tmp, Dynamic * tmp2)
{
// 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;
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_lex(e, regles, "blanc", tmp); // 1
rlex.nomregle = rg_lex(e, regles, "nomregle", tmp); // 2
rlex.debut = rg_lex(e, regles, "debut", tmp); // 3
rlex.fin = rg_lex(e, regles, "fin", tmp); // 4
rlex.occ = rg_lex(e, regles, "occ", tmp); // 5
rlex.infini = rg_lex(e, regles, "infini", tmp); // 6
rlex.commentaire = rg_lex(e, regles, "commentaire", tmp); // 7
rlex.intervalle = rg_lex(e, regles, "intervalle", tmp); // 8
rlex.hexa = rg_lex(e, regles, "hexa", tmp); // 9
rlex.car = rg_lex(e, regles, "car", tmp); // 10
rlex.reste = rg_lex(e, regles, "reste", tmp); // 11
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, 10, DYN_NONE, DYN_NONE);
int nbval = dynDcount(e, valex, cVM, 2, cFM);
ent16 regle;
dynSetLen(e, trav, 0);
dynSetLen(e, encours, 0);
for(int ival = nbval; ival > 0; ival--)
{
/* suppression des regles 1 et 7 (blanc et commentaire) */
dynField(e, valex, tmp, 2, ival, cFM, cVM, 1);
regle = dynToNum(e, tmp, DYN_FALSE, 0);
if(regle == rlex.blanc || regle == rlex.commentaire)
{
dynDel(e, valex, 1, ival, cFM, cVM, 1);
dynDel(e, valex, 2, ival, cFM, cVM, 1);
dynDel(e, valex, 3, ival, cFM, cVM, 1);
}
else
{
if(dynCtrl(e, trav, trav->mLg + 2, TRUE) != DYN_OK)
return DYN_ERR;
if(trav->mLg > 0)
memcopie(trav->mPtr + 2, trav->mPtr, trav->mLg);
*(ent16 *)(trav->mPtr) = regle;
dynSetLen(e, trav, trav->mLg + 2);
}
}
//dynDel(e, valex, 2, DYN_NONE, cFM, DYN_NONE, 1);
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
//for(int i=1;i<=trav->mLg/2;i++) printf("%d,",nreg(i)); printf("\n");
/* debut d'analyse des tokens : nomregle */
if(nreg(1) != rlex.nomregle)
{
dynField(e, valex, tmp, 3, 1, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_RULENAME_EXPECTED;
}
/* liste de et/ou */
for(ent16 n = 2;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == rlex.debut || regle == rlex.car) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
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 == 2)
dynStoreSz(e, valex, 4, DYN_NONE, "", 0, cFM, DYN_NONE);
else
dynConcatSz(e, valex, ";", 1);
/* */
if(regle == rlex.car)
{
/* 1 caractere = (1,1,car) (raccourci d'ecriture) */
dynConcatSz(e, valex, "1,1,", 4);
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(e, valex, tmp);
n++;
continue;
}
if(nreg(n+1) == rlex.occ && (nreg(n+2) == rlex.occ || nreg(n+2) == rlex.infini)) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
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);
while(n1 == rlex.car || n1 == rlex.hexa || ((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa)))
{
dynConcatSz(e, valex, unefois, DYN_LGNONE);
if((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa))
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
if(n1 == 10)
dynConcat(e, valex, tmp);
else
{
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, 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;
#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"
@@ -401,10 +449,12 @@ WAPIDECL void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
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;
@@ -419,6 +469,13 @@ WAPIDECL 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)
@@ -466,6 +523,9 @@ WAPIDECL 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;
@@ -485,10 +545,15 @@ WAPIDECL 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);
//
@@ -526,6 +591,9 @@ WAPIDECL 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;
@@ -545,6 +613,36 @@ WAPIDECL 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)
@@ -569,11 +667,13 @@ WAPIDECL long compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile)
init_reg_lex(e, &regles, &tmp);
dynErase(e, fichier_lex, "\r");
dynRemove(e, fichier_lex, NULL, 0, DYN_TRUE);
while(dynRemove(e, fichier_lex, &ligne, 10, DYN_FALSE) > -1 && ret == 0)
while(dynRemove(e, fichier_lex, &ligne, cLF, DYN_FALSE) > -1 && ret == 0)
{
lex(e, &regles, &ligne, &tmp); // tmp au format "valex" : chaine/noregle/position
ret = parse_lex(e, &tmp, compile, &tmp1, &tmp2, &tmp3, 1); /* 1 = runtime on (appel depuis lexMod), pas de printf */
}
if(ret == OK)
ret = compile_maj_etat(e, compile, &tmp, &tmp1, &tmp2);
cr = ret;
}
//
@@ -595,7 +695,7 @@ WAPIDECL long compile_like(env * e, Dynamic * like, Dynamic * compile)
'?' : 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\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
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);
/* */
@@ -626,8 +726,8 @@ WAPIDECL long compile_like(env * e, Dynamic * like, Dynamic * compile)
else
{
/* ajout necessaire au compile lex */
dynInsSz(e, compile, 1, DYN_NONE, "like,1,other,2", 14, 10, DYN_NONE);
dynConcatSz(e, compile, "\n1,1,00-FF", 10);
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;
}
}
+8 -5
View File
@@ -23,11 +23,12 @@
#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_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"
@@ -38,8 +39,10 @@ WAPIDECL long parse_lex(env * e, Dynamic * valex, Dynamic * resultat, Dynamic *
/* */
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);
+123 -85
View File
@@ -32,20 +32,33 @@
#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"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -56,163 +69,188 @@ 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
//
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "compile", 7))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramLexRules->type != VAR_DYNAMIC || paramCompiledRules->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, compile_lex(e, param1, param2));
if(exc == OK && param3 != NULL)
if(param3->type == VAR_HASHTABLE)
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;)
{
var * v = &e->int_number;
hashtable_clear(e, param3);
long cpt, nb = dynDcount(e, param2, ',', 1, 10);
for(cpt = 1; cpt < nb;)
{
dynField(e, param2, &e->tmp_dynamic, 1, cpt++, 10, ',', 1);
e->int_number.num = dynFieldAsNumber(e, param2, 1, cpt++, 10, ',') * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, e->tmp_dynamic.mPtr), &v);
}
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))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC) // rules - input - result
else if(paramCompiledRules->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
lex(e, param1, param2, param3);
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))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* 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(param1->type != VAR_DYNAMIC) // liste token trouves
exc = EX_MODPARAM;
else if(param2->type != VAR_NUMBER && param2->type != VAR_DYNAMIC) // indice
exc = EX_MODPARAM;
else if(param3->type != VAR_HASHTABLE) // hashtable contenant les 3 resultats : valeur (clair), no regle et position dans la source (input de analyze)
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, param2, &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, param1, 2, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, "ruleNumber"), &n);
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, param1, 1, indice, w);
dynExtractSubField(e, paramTokenList, 1, indice, w);
hex2str(e, w, v);
}
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, "ruleValue"), &v);
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenValue"), &v);
/* */
if(n->num != 0)
n->num = dynExtractSubFieldAsNumber(e, param1, 3, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, "ruleLocation"), &n);
n->num = dynExtractSubFieldAsNumber(e, paramTokenList, 3, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenLocation"), &n);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
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;
}
+122 -4
View File
@@ -2,7 +2,7 @@
// !! ne pas mettre de caracteres \r dans les constantes ci-dessous !!
// fichiers lex
static char file_lexlex[] = "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11\n"
/*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"
@@ -13,10 +13,24 @@ static char file_lexlex[] = "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,com
"1,1,2D\n"
"1,1,23;2,2,30-39:41-46\n"
"1,1,21-7E\n"
"1,1,00-FF";
"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\n"
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"
@@ -43,4 +57,108 @@ static char file_debuglex[] = "blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supp
"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\n1,-1,20:09\n1,1,3B;0,-1,00-FF\n1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n1,1,65;1,1,6E;1,1,64\n1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n1,1,73;1,1,75;1,1,62\n1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n1,1,69;1,1,66\n1,1,74;1,1,68;1,1,65;1,1,6E\n1,1,65;1,1,6C;1,1,73;1,1,65\n1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n1,1,64;1,1,6F\n1,1,63;1,1,61;1,1,6C;1,1,6C\n1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n1,1,69;1,1,6E\n1,1,6C;1,1,69;1,1,6B;1,1,65\n1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n1,1,6E;1,1,6F;1,1,70\n1,1,70;1,1,61;1,1,72;1,1,74\n1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n1,1,65;1,1,63;1,1,68;1,1,6F\n1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n1,1,6C;1,1,65;1,1,74\n1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n1,1,6E;1,1,65;1,1,77\n1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n1,1,74;1,1,68;1,1,69;1,1,73\n1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n1,1,68;1,1,6F;1,1,6C;1,1,64\n1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n1,1,69;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,61;1,1,63\n1,1,61;1,1,62;1,1,73\n1,1,6E;1,1,65;1,1,67\n1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,73;1,1,71;1,1,72;1,1,74\n1,1,65;1,1,78;1,1,70\n1,1,74;1,1,79;1,1,70;1,1,65\n1,1,6C;1,1,65;1,1,6E\n1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n1,1,3D\n1,1,23\n1,1,3E\n1,1,3C\n1,1,3E;1,1,3D\n1,1,3C;1,1,3D\n1,1,61;1,1,6E;1,1,64\n1,1,6F;1,1,72\n1,1,6E;1,1,6F;1,1,74\n1,1,28\n1,1,29\n1,1,7B\n1,1,7D\n1,1,5B\n1,1,5D\n1,1,21\n1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n1,1,22;0,765,20-21:23-EF;1,1,22\n1,1,27;0,765,20-26:28-EF;1,1,27\n1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,40;1,-1,61-7A\n1,13,30-39;1,1,2E;0,5,30-39\n1,13,30-39\n1,1,2D\n1,1,2B\n1,1,2A\n1,1,2F\n1,1,5C\n1,1,25\n1,1,3A\n1,1,2C\n1,1,2E\n1,1,26\n1,1,00-FF";
static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n"
"1,-1,20:09\n"
"1,1,3B;0,-1,00-FF\n"
"1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n"
"1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n"
"1,1,65;1,1,6E;1,1,64\n"
"1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n"
"1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n"
"1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n"
"1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n"
"1,1,73;1,1,75;1,1,62\n"
"1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n"
"1,1,69;1,1,66\n"
"1,1,74;1,1,68;1,1,65;1,1,6E\n"
"1,1,65;1,1,6C;1,1,73;1,1,65\n"
"1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n"
"1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n"
"1,1,64;1,1,6F\n"
"1,1,63;1,1,61;1,1,6C;1,1,6C\n"
"1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n"
"1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n"
"1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n"
"1,1,6C;1,1,6F;1,1,6F;1,1,70\n"
"1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n"
"1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n"
"1,1,69;1,1,6E\n"
"1,1,6C;1,1,69;1,1,6B;1,1,65\n"
"1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n"
"1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n"
"1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n"
"1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n"
"1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n"
"1,1,6E;1,1,6F;1,1,70\n"
"1,1,70;1,1,61;1,1,72;1,1,74\n"
"1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n"
"1,1,65;1,1,63;1,1,68;1,1,6F\n"
"1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n"
"1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n"
"1,1,6C;1,1,65;1,1,74\n"
"1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n"
"1,1,6E;1,1,65;1,1,77\n"
"1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n"
"1,1,74;1,1,68;1,1,69;1,1,73\n"
"1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n"
"1,1,68;1,1,6F;1,1,6C;1,1,64\n"
"1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n"
"1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n"
"1,1,69;1,1,6E;1,1,74\n"
"1,1,66;1,1,72;1,1,61;1,1,63\n"
"1,1,61;1,1,62;1,1,73\n"
"1,1,6E;1,1,65;1,1,67\n"
"1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,73;1,1,71;1,1,72;1,1,74\n"
"1,1,65;1,1,78;1,1,70\n"
"1,1,74;1,1,79;1,1,70;1,1,65\n"
"1,1,6C;1,1,65;1,1,6E\n"
"1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n"
"1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n"
"1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n"
"1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n"
"1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n"
"1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n"
"1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n"
"1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n"
"1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n"
"1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n"
"1,1,3D\n"
"1,1,23\n"
"1,1,3E\n"
"1,1,3C\n"
"1,1,3E;1,1,3D\n"
"1,1,3C;1,1,3D\n"
"1,1,61;1,1,6E;1,1,64\n"
"1,1,6F;1,1,72\n"
"1,1,6E;1,1,6F;1,1,74\n"
"1,1,28\n"
"1,1,29\n"
"1,1,7B\n"
"1,1,7D\n"
"1,1,5B\n"
"1,1,5D\n"
"1,1,21\n"
"1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n"
"1,1,22;0,765,20-21:23-EF;1,1,22\n"
"1,1,27;0,765,20-26:28-EF;1,1,27\n"
"1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n"
"1,1,40;1,-1,61-7A\n"
"1,13,30-39;1,1,2E;0,5,30-39\n"
"1,13,30-39\n"
"1,1,2D\n"
"1,1,2B\n"
"1,1,2A\n"
"1,1,2F\n"
"1,1,5C\n"
"1,1,25\n"
"1,1,3A\n"
"1,1,2C\n"
"1,1,2E\n"
"1,1,26\n"
"1,1,00-FF";
+85 -70
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -29,24 +29,29 @@
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "lzw.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextLzw cl;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -57,125 +62,135 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
/* */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
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
initLzw(e, &p_etat->cl);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initLzw(e, &p_etat->cl);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeLzw(e, &p_etat->cl);
//*** FIN du code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
/* compression du clair de param, en une fois */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPlaintextThenCompressed = getParam(e, "plaintextThenCompressed", 23);
if(paramPlaintextThenCompressed == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
else if(paramPlaintextThenCompressed->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, setLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
exc = setError(p_etat, setLzw(e, paramPlaintextThenCompressed, &p_etat->cl, 0)); /* compression compatible PDF (mais pas GIF), 0 : en une fois */
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
/* decompression du code de param, en une fois */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramCompressedThenPlaintext = getParam(e, "compressedThenPlaintext", 23);
var * paramReverse = getParam(e, "reverse", 7);
if(paramCompressedThenPlaintext == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
else if(paramCompressedThenPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
p_etat->cl.inverse = FALSE;
if(param2 != NULL)
if(paramReverse != NULL)
{
if(param2->type == VAR_DYNAMIC || param2->type == VAR_NUMBER)
if(paramReverse->type == VAR_DYNAMIC || paramReverse->type == VAR_NUMBER)
{
number inv;
if(var_conv_num(e, param2, &inv))
if(var_conv_num(e, paramReverse, &inv))
p_etat->cl.inverse = (inv != 0 ? TRUE : FALSE);
}
}
exc = setError(p_etat, getLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
exc = setError(p_etat, getLzw(e, paramCompressedThenPlaintext, &p_etat->cl, 0)); /* decompression compatible PDF (et GIF si reverse = TRUE), 0 : en une fois */
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
/* **************************************************************************************************** */
+50
View File
@@ -0,0 +1,50 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
/* est inclus dans tous les modules xxxMod.c */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
static var * getParam(env * e, const char * name, int lg)
{
/* recherche parametre nomme "name" */
var * p = &e->v;
p->type = VAR_NULL;
e->nom64[0] = 0; e->nom64[1] = 0; e->nom64[2] = 0;
if(lg > 0 && lg < 25)
strncpy((char *)e->nom64, name, lg);
(e->pop)(e, p);
if(p->type == VAR_PARAM)
return (var *)(p->ptr);
else
{
if(e->exception == EX_BUFOVF)
e->exception = OK; /* parametre non trouve : exception BUFOVF => pas d'exception, gere avec le retour NULL ici, par l'appelant */
return NULL;
}
}
+236
View File
@@ -0,0 +1,236 @@
//ent64 ENT64_MAX = 999999999999999999ull; /* 18 chiffres dont 5 decimales */
//ent32 FACTEUR = 100000;
ent64 mul64(ent64s a, ent64s b, ent64s * r)
{
/* recherche signe du resultat + passage en positif */
int negatif = 0;
if(a < 0)
{
negatif = 1 - negatif;
a = -a;
}
if(b < 0)
{
negatif = 1 - negatif;
b = -b;
}
/* multiplication */
ent64 ap = a, bp = b;
ent64 aph = (ap >> 32), apl = (ap & 0xFFFFFFFFull);
ent64 bph = (bp >> 32), bpl = (bp & 0xFFFFFFFFull);
ent64 ab_hi = aph * bph;
ent64 ab_lo = apl * bpl;
ent64 ab_lo_debut = ab_lo;
ent64 aphbpl = aph * bpl;
ent64 aplbph = apl * bph;
ab_hi += (aphbpl >> 32) + (aplbph >> 32); /* pas d'overflow ! */
ent64 sum = (aphbpl & 0xFFFFFFFFull) + (aplbph & 0xFFFFFFFFull); /* si overflow ici (quad haut non nul), increment ab_hi */
ab_hi += (sum >> 32);
ab_lo += (sum & 0xFFFFFFFFull) << 32; /* si overflow ici, incrementer ab_hi ; en non signe c'est le test avec inferieur qui suit ! */
if(ab_lo < ab_lo_debut)
ab_hi++; /* retenue */
/* division par le facteur 100000 */
ent64 ab_hi_hi = (ab_hi >> 32);
ent64 ab_hi_lo = (ab_hi & 0xFFFFFFFF);
ent64 ab_lo_hi = (ab_lo >> 32);
ent64 ab_lo_lo = (ab_lo & 0xFFFFFFFF);
ent32 q_hi_hi = ab_hi_hi / FACTEUR;
ent64 reste = ab_hi_hi % FACTEUR;
ent32 q_hi_lo = ((reste << 32) | ab_hi_lo) / FACTEUR;
reste = ((reste << 32) | ab_hi_lo) % FACTEUR;
ent32 q_lo_hi = ((reste << 32) | ab_lo_hi) / FACTEUR;
reste = ((reste << 32) | ab_lo_hi) % FACTEUR;
ent32 q_lo_lo = ((reste << 32) | ab_lo_lo) / FACTEUR;
reste = ((reste << 32) | ab_lo_lo) % FACTEUR;
ab_hi = ((ent64)q_hi_hi << 32) | (ent64)q_hi_lo;
ab_lo = ((ent64)q_lo_hi << 32) | (ent64)q_lo_lo;
/* si reste >= FACTEUR/2 => faire +1, ce qui revient a tester >= au lieu de > */
/* test final */
if(ab_hi > 0)
return EX_NUMOVF; /* overflow */
if(reste >= FACTEUR / 2)
{
if(ab_lo >= ENT64_MAX)
return EX_NUMOVF; /* overflow */
else
ab_lo++;
}
else if(ab_lo > ENT64_MAX)
return EX_NUMOVF; /* overflow */
/* */
if(negatif)
*r = -(ent64s)ab_lo;
else
*r = (ent64s)ab_lo;
return OK; /* pas d'overflow */
}
ent64 div64(ent64s a, ent64s b, ent64s * q, ent64s * r, int div_ent)
{
if(b == 0)
return EX_DIV0;
/* a/b => a * 100000 / b ; div_ent # 0 si division entiere (methode ici evite l'algorithme de Knuth D en base 2^32) */
/* gerer les signes => travail en positif (idem multiplication) */
int negatif = 0, divid_neg = 0;
if(a < 0)
{
negatif = 1 - negatif;
a = -a;
divid_neg = 1;
}
if(b < 0)
{
negatif = 1 - negatif;
b = -b;
}
ent64 ap = a, bp = b;
ent64 q_lo = ap / bp;
ent64 reste_debut = ap % bp;
if(q_lo > ENT64_MAX / FACTEUR)
return EX_NUMOVF;
q_lo *= FACTEUR;
ent64 reste = reste_debut;
if( ! div_ent)
{
ent64 reste10;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 10000ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 1000ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 100ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp) * 10ull;
reste = reste10 % bp;
reste10 = (reste << 3) + (reste << 1); /* x 10 */
q_lo += (reste10 / bp);
reste = reste10 % bp;
if(reste >= bp - reste)
{
if(q_lo >= ENT64_MAX)
return EX_NUMOVF;
else
q_lo++;
}
}
if(q)
{
if(negatif)
*q = -(ent64s)q_lo;
else
*q = (ent64s)q_lo;
}
/* reste est du signe du dividende (si demande en parametre) */
if(r)
{
if(divid_neg)
*r = -(ent64s)reste;
else
*r = (ent64s)reste;
}
///* multiplication par 100000 */
//ent64 ap = a, bp = b;
//ent64 a_hi = (ap >> 32) * FACTEUR;
//ent64 a_lo = (ap & 0xFFFFFFFFull) * FACTEUR;
//ent64 a_lo_debut = a_lo;
//a_lo += (a_hi << 32);
//a_hi >>= 32;
//if(a_lo < a_lo_debut)
// a_hi++;
///* division par b */
//ent64 reste = a_hi;
//ent32 a_lo_hi = a_lo >> 32;
//ent32 a_lo_lo = a_lo & 0xFFFFFFFFull;
//ent64 q_hi = ((ent64)reste << 32) | a_lo_hi;
//reste = q_hi % bp;
//q_hi /= bp;
//ent64 q_lo = ((ent64)reste << 32) | a_lo_lo;
//reste = q_lo % bp;
//q_lo /= bp;
///* */
//if(q_hi > 0)
// return EX_NUMOVF; /* overflow */
//if(reste >= bp - reste)
//{
// if(q_lo >= ENT64_MAX)
// return EX_NUMOVF; /* overflow*/
// else
// q_lo++; /* arrondi superieur */
//}
//else if(q_lo > ENT64_MAX)
// return EX_NUMOVF; /* overflow */
///* gerer les signes du quotient (si demande en parametre) */
//if(q)
//{
// if(negatif)
// *q = -(ent64s)q_lo;
// else
// *q = (ent64s)q_lo;
//}
///* reste est du signe du dividende (si demande en parametre) */
//if(r)
//{
// if(divid_neg)
// *r = -(reste / FACTEUR);
// else
// *r = reste / FACTEUR;
//}
return OK;
}
ent64 add64(ent64s a, ent64s b, ent64s * s)
{
ent64 r;
if(a >= 0 && b >= 0)
{
r = (ent64)a + (ent64)b;
if(r > ENT64_MAX || r < (ent64)a)
return EX_NUMOVF; /* overflow*/
else
*s = (ent64s)r;
}
else if (a < 0 && b < 0)
{
r = (ent64)(- a) + (ent64)(- b);
if(r > ENT64_MAX || r < (ent64)(- a))
return EX_NUMOVF; /* overflow*/
else
*s = - (ent64s)r;
}
else
{
*s = a + b; /* pas d'overflow possible avec signes differents */
}
return OK;
}
ent64 sub64(ent64s a, ent64s b, ent64s * s)
{
ent64 r;
if(a >= 0 && b < 0)
{
r = (ent64)a + (ent64)(- b);
if(r > ENT64_MAX || r < (ent64)a)
return EX_NUMOVF; /* overflow*/
else
*s = (ent64s)r;
}
else if (a < 0 && b >= 0)
{
r = (ent64)(- a) + (ent64)(b);
if(r > ENT64_MAX || r < (ent64)(b))
return EX_NUMOVF; /* overflow*/
else
*s = - (ent64s)r;
}
else
{
*s = a - b; /* pas d'overflow possible avec signes egaux */
}
return OK;
}
+7 -2
View File
@@ -54,11 +54,13 @@ typedef struct
Dynamic mPdf; /* PDF en cours de constitution */
Dynamic mPage; /* page en cours */
Dynamic mXref; /* liste des xref du PDF en cours (<1> contient le titre et les dimensions des images) */
Dynamic mImg; /* images en FM, en hexa, BMP 24/32 bpp uniquement (codage RGB) */
Dynamic mImg; /* images en FM, en hexa, BMP 24/32 bpp uniquement (codage RGB) */
Dynamic mInfoPage; /* quand nb pages pas connu a l'init, contient le num obj de chaque page */
long mNbPage; /* nb de pages total du PDF */
long mFormat; /* A4 ou A3 et Paysage ou portrait */
long mLarg, mHaut; /* largeur/hauteur de la page en (mm x 10), selon le format */
long mNbObj; /* pour xref */
long mNbFont, mNbImg, mNbObjFixe;
long mNumPage; /* numero page en cours */
long mLmarg; /* marge gauche en mm x 10 */
@@ -68,7 +70,9 @@ typedef struct
long mDimFont; /* taille fonte */
long mDimFontCadre;
long mDimLig;
Dynamic mFont; /* nom des 14 fontes standards */
Dynamic mFont; /* nom des 14 fontes standards */
Dynamic mEan128; /* codage graphique du cab ean128 */
modContextLzw mCtxLzw; /* gestion compression page lzw */
@@ -83,6 +87,7 @@ 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);
+214 -161
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -30,25 +30,35 @@
#include "var.h"
#include "hashtable.h"
/* ============================================================================================= */
#include "pdf.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextPdf cp;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_PDF_INTERNAL_ERR = 1,
EXMOD_PDF_IMGFORMAT = 2,
EXMOD_PDF_PARAMETERSET = 3,
EXMOD_NB = 3
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Internal error",
"Image format unsupported (BMP/GIF only)",
"Incorrect parameterSet's membre"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -59,38 +69,31 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initPdf(e, &p_etat->cp);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initPdf(e, &p_etat->cp);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
@@ -98,281 +101,331 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
//*** code specifique ici
freePdf(e, &p_etat->cp);
// fin liberation specifique module avant arret process
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "beginDoc", 8))
{
// nouveau document pdf
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
else if(paramPdfParameterSet->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// lire les infos necessaires a la creation d'un nouveau doc. pdf :
// titre, nb pages, format, fontes utilisees
var * titre, * fontes, * nbPage, * format;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fontes"), &fontes);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Pages"), &nbPage);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Format"), &format);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Title"), &titre);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Fonts"), &fontes);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Pages"), &nbPage);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Format"), &format);
if(titre && fontes && nbPage && format)
{
if(titre->type == VAR_DYNAMIC && fontes->type == VAR_DYNAMIC && nbPage->type == VAR_NUMBER && format->type == VAR_NUMBER)
if(titre->type == VAR_DYNAMIC && fontes->type == VAR_DYNAMIC &&
(nbPage->type == VAR_NUMBER || nbPage->type == VAR_DYNAMIC) && (format->type == VAR_NUMBER || format->type == VAR_DYNAMIC))
{
number nnbPage, nformat;
if( var_conv_num(e, nbPage, &nnbPage) && var_conv_num(e, format, &nformat) )
exc = setError(p_etat, ! newPdf(e, &p_etat->cp, titre, nnbPage / NUM_FACTEUR, nformat / NUM_FACTEUR, fontes));
exc = setError(p_etat, newPdf(e, &p_etat->cp, titre, nnbPage / NUM_FACTEUR, nformat / NUM_FACTEUR, fontes) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "endDoc", 6))
{
// finalise le document pdf, et renvoi le contenu dans param1
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfContent = getParam(e, "pdfContent", 10);
if(paramPdfContent == NULL)
exc = EX_MODPARAM;
else
{
int cr = endPdf(e, &p_etat->cp);
if(cr)
{
var_let(e, param1, getPdf(e, &p_etat->cp), FALSE, FALSE);
}
exc = setError(p_etat, ! cr);
var_let(e, paramPdfContent, getPdf(e, &p_etat->cp), FALSE, FALSE);
exc = setError(p_etat, cr ? OK : EXMOD_PDF_INTERNAL_ERR);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addPage", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
// ajouter la page en cours au doucment pdf
exc = setError(p_etat, ! setPdfPage(e, &p_etat->cp, 1)); // 1 = avec compression ; parametrer ?
/* get param in the right order */
// ajouter la page en cours au doucment pdf
exc = setError(p_etat, setPdfPage(e, &p_etat->cp, 1) ? OK : EXMOD_PDF_INTERNAL_ERR); // 1 = avec compression ; parametrer ?
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addText", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == 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(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramString->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// ajouter le texte
var * x, * y, * w, * h; // cadre englobant
var * fonte, * taille, * couleur;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fonte"), &fonte);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Taille"), &taille);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Couleur"), &couleur);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Font"), &fonte);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Size"), &taille);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Color"), &couleur);
if(x && y && w && h && fonte && taille && couleur)
{
number nx, ny, nw, nh, nfonte, ntaille, ncouleur;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
var_conv_num(e, fonte, &nfonte) && var_conv_num(e, taille, &ntaille) && var_conv_num(e, couleur, &ncouleur) )
exc = setError(p_etat, ! setPdfText(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
nfonte / NUM_FACTEUR, ntaille / NUM_FACTEUR, ncouleur / NUM_FACTEUR, param2)); // param2 = texte
exc = setError(p_etat, setPdfText(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
nfonte / NUM_FACTEUR, ntaille / NUM_FACTEUR, ncouleur / NUM_FACTEUR, paramString) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
else if(modFnIs(e, "delImage", 8))
/* ---------------------------------------------------- */
else if(modFnIs(e, "addCab128", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
var * paramString = getParam(e, "string", 6);
if(paramPdfParameterSet == NULL || paramString == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER && param1->type != VAR_DYNAMIC)
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramString->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number indice;
if(var_conv_num(e, param1, &indice))
exc = setError(p_etat, ! pdfDeleteImage(e, &p_etat->cp, indice / NUM_FACTEUR));
// ajouter le texte
var * x, * y, * h; // position et hauteur du CAB
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
if(x && y && h)
{
number nx, ny, nh;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, h, &nh) )
exc = setError(p_etat, setCab128(e, &p_etat->cp, paramString, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nh / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addGraph", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
else if(paramPdfParameterSet->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * w, * h; // cadre englobant
var * couleurTrait, * couleurRemplissage, * epaisseur, * pointille, * type;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CouleurTrait"), &couleurTrait);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CouleurRemplissage"), &couleurRemplissage);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "EpaisseurTrait"), &epaisseur);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Pointille"), &pointille);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Type"), &type);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "StrokeColor"), &couleurTrait);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "FillColor"), &couleurRemplissage);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "LineThickness"), &epaisseur);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Dotted"), &pointille);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Type"), &type);
if(x && y && w && h && couleurTrait && couleurRemplissage && epaisseur && pointille && type)
{
number nx, ny, nw, nh, ntrait, nrempl, nepais, npoint;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
type->type == VAR_DYNAMIC && var_conv_num(e, couleurTrait, &ntrait) && var_conv_num(e, couleurRemplissage, &nrempl) &&
var_conv_num(e, epaisseur, &nepais) && var_conv_num(e, pointille, &npoint) )
exc = setError(p_etat, ! setPdfGraph(e, &p_etat->cp, *type->mPtr, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
ntrait / NUM_FACTEUR, nrempl / NUM_FACTEUR, nepais / NUM_FACTEUR, npoint / NUM_FACTEUR));
exc = setError(p_etat, setPdfGraph(e, &p_etat->cp, *type->mPtr, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
ntrait / NUM_FACTEUR, nrempl / NUM_FACTEUR, nepais / NUM_FACTEUR, npoint / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addImage", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
else if(paramPdfParameterSet->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * img; // cadre englobant et n° image
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Image"), &img);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "ImageIndex"), &img);
if(x && y && img)
{
number nx, ny, nimg;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, img, &nimg) )
exc = setError(p_etat, ! setPdfImage(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nimg / NUM_FACTEUR));
exc = setError(p_etat, setPdfImage(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nimg / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "loadImage", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramImage = getParam(e, "image", 5);
var * paramFormat = getParam(e, "format", 6);
if(paramImage == NULL || paramFormat == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramImage->type != VAR_DYNAMIC || paramFormat->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynCompare(e, param2, CMP_EQ, "BMP", 3))
exc = setError(p_etat, ! pdfLoadImageBmp(e, &p_etat->cp, param1));
else if(dynCompare(e, param2, CMP_EQ, "GIF", 3))
exc = setError(p_etat, ! pdfLoadImageGif(e, &p_etat->cp, param1));
if(dynCompare(e, paramFormat, CMP_EQ, "BMP", 3))
exc = setError(p_etat, pdfLoadImageBmp(e, &p_etat->cp, paramImage) ? OK : EXMOD_PDF_INTERNAL_ERR);
else if(dynCompare(e, paramFormat, CMP_EQ, "GIF", 3))
exc = setError(p_etat, pdfLoadImageGif(e, &p_etat->cp, paramImage) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_IMGFORMAT);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "delImage", 8))
{
/* get param in the right order */
var * paramImage = getParam(e, "imageIndex", 10);
if(paramImage == NULL)
exc = EX_MODPARAM;
else if(paramImage->type != VAR_NUMBER && paramImage->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number indice;
if(var_conv_num(e, paramImage, &indice))
exc = setError(p_etat, pdfDeleteImage(e, &p_etat->cp, indice / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ---------------------------------------------------- */
else if(modFnIs(e, "listing", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
var * paramTextThenPdfContent = getParam(e, "textThenPdfContent", 18);
if(paramPdfParameterSet == NULL || paramTextThenPdfContent == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramTextThenPdfContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
var * titre, * format;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Format"), &format);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Title"), &titre);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Format"), &format);
if(titre && format)
{
if(titre->type == VAR_DYNAMIC && format->type == VAR_NUMBER)
if(titre->type == VAR_DYNAMIC && (format->type == VAR_NUMBER || format->type == VAR_DYNAMIC))
{
int cr = pdfList(e, &p_etat->cp, titre, param2, format->num / NUM_FACTEUR);
if(cr)
number nformat;
if( var_conv_num(e, format, &nformat) )
{
var_let(e, param2, getPdf(e, &p_etat->cp), FALSE, FALSE);
int cr = pdfList(e, &p_etat->cp, titre, paramTextThenPdfContent, nformat / NUM_FACTEUR);
if(cr)
var_let(e, paramTextThenPdfContent, getPdf(e, &p_etat->cp), FALSE, FALSE);
exc = setError(p_etat, cr ? OK : EXMOD_PDF_INTERNAL_ERR);
}
exc = setError(p_etat, ! cr);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+162 -28
View File
@@ -266,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"
@@ -337,6 +344,33 @@ static void convertHexaRGBToBinLzw(env * e, modContextPdf * ctxPdf)
setLzw(e, &ctxPdf->mTmp2, &ctxPdf->mCtxLzw, 0);
}
static void graphCab128(env * e, modContextPdf * ctxPdf, long code, long * x, long y, long h)
{
long ec = 0, x1, i, largeur = 3; /* largeur des barres, pour un 1 */
long nb = (code == 106 ? 13 : 11); /* code stop = 13 bits, les autres = 11 bits */
code = code * 11;
for(i = 0; i < nb; i++, code++)
{
if(ctxPdf->mEan128.mPtr[code] == '1')
{
if( ! ec)
{
ec = 1;
x1 = *x;
}
}
else if(ec)
{
ec = 0;
setPdfGraph(e, ctxPdf, 'R', x1, y, *x - x1, h, -1, RGB(0,0,0), 0, 0);
}
/* */
*x += largeur;
}
if(ec)
setPdfGraph(e, ctxPdf, 'R', x1, y, *x - x1, h, -1, RGB(0,0,0), 0, 0);
}
/* PUBLIC ************************************************************************/
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf)
{
@@ -357,12 +391,32 @@ WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf)
ctxPdf->mPdf.type = VAR_DYNAMIC;
dynInit(e, &ctxPdf->mXref, 1024);
dynInit(e, &ctxPdf->mImg, 2048);
dynInit(e, &ctxPdf->mInfoPage, 1024);
dynInit(e, &ctxPdf->mEan128, 1200);
/* nom des fontes standards */
dynLet(e, &ctxPdf->mFont, "Courier,Courier-Bold,Courier-BoldOblique,Courier-Oblique,Helvetica,Helvetica-Bold,Helvetica-BoldOblique,Helvetica-Oblique,"
"Times-Roman,Times-Bold,Times-Italic,Times-BoldItalic,Symbol,ZapfDingbats", DYN_LGNONE);
dynConvert(e, &ctxPdf->mFont, ",", sFM);
//
initLzw(e, &ctxPdf->mCtxLzw);
//
// code ean 128 : https://fr.wikipedia.org/wiki/Code_128
// Checksum = (StartCode + 1 x valeur1 + 2 x valeur2 + 3 x valeur3 + ...) modulo 103 (valeur de 0 a 102)
dynLet(e, &ctxPdf->mEan128,
"11011001100110011011001100110011010010011000100100011001000100110010011001000100110001001000110010011001001000" // 0 9
"11001000100110001001001011001110010011011100100110011101011100110010011101100100111001101100111001011001011100" // 10 19
"11001001110110111001001100111010011101101110111010011001110010110011100100110111011001001110011010011100110010" // 20 29
"11011011000110110001101100011011010100011000100010110001000100011010110001000100011010001000110001011010001000" // 30 39
"11000101000110001000101011011100010110001110100011011101011101100010111000110100011101101110111011011010001110" // 40 49
"11000101110110111010001101110001011011101110111010110001110100011011100010110111011010001110110001011100011010" // 50 59
"11101111010110010000101111000101010100110000101000011001001011000010010000110100001011001000010011010110010000" // 60 69
"10110000100100110100001001100001010000110100100001100101100001001011001010000111101110101100001010010001111010" // 70 79
"10100111100100101111001001001111010111100100100111101001001111001011110100100111100101001111001001011011011110" // 80 89
"11011110110111101101101010111100010100011110100010111101011110100010111100010111101010001111010001010111011110" // 90 99
"1011110111011101011110111101011101101000010011010010000110100111001100011101011", 1180); // 100 106 (106 sur 13 bits au lieu de 11 pour tous les autres)
// codes 0 - 94 : codes ascii de 32 a 126 (code 128B)
// codes 95:DEL 96:FNC3 97:FNC2 98:SHIFTA 99:CODEC 100:CODEB 101:CODEA 102:FNC1 103:StartA 104:StartB 105:StartC 106:Stop(13 bits)
// code EAN128B : startB_104 + valeur1 + valeur2 + valeur3 + ... + checksum + Stop_106
}
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf)
@@ -377,15 +431,17 @@ WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf)
dynFree(e, &ctxPdf->mPdf);
dynFree(e, &ctxPdf->mXref);
dynFree(e, &ctxPdf->mImg);
dynFree(e, &ctxPdf->mInfoPage);
dynFree(e, &ctxPdf->mEan128);
}
WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts)
{
long i, j, cpt, nbp;
long nb_img, nb_obj_entete, nb_font, nb_obj_fixe = 3;
long nb_img, nb_obj_entete, nb_font;
int cr = TRUE;
/* controles */
if(nb_page < 1)
if(nb_page < 0)
return FALSE;
/* */
switch(format)
@@ -425,9 +481,11 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
/* */
nb_font = dynDcount(e, fonts, cFM, DYN_NONE, DYN_NONE);
nb_img = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE);
nb_obj_entete = nb_obj_fixe + nb_font + nb_img;
ctxPdf->mNbObjFixe = 3;
nb_obj_entete = ctxPdf->mNbObjFixe + nb_font + nb_img;
ctxPdf->mNbObj = nb_obj_entete + ctxPdf->mNbPage;
ctxPdf->mNumPage = 0;
ctxPdf->mNbImg = nb_img;
//
dynLet(e, &ctxPdf->mPdf, "%PDF-1.2\r\n", DYN_LGNONE);
// objet racine root
@@ -439,24 +497,27 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1); /* titre "echape" */
dynConcatSz(e, &ctxPdf->mPdf, ") /CreationDate (", DYN_LGNONE);
dynSetLen(e, &ctxPdf->mTmp1, 0); // empty => oconv will convert time of the day
dynOconv(e, &ctxPdf->mTmp1, &ctxPdf->mTmp2, "DYMDhms");
dynOconv(e, &ctxPdf->mTmp1, &ctxPdf->mTmp2, "DYMDhmsZ");
dynConcatSz(e, &ctxPdf->mPdf, "D:", 2);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
//dynConcatSz(e, &ctxPdf->mPdf, "20000101140000", DYN_LGNONE); // TODO date courante YMDhms dynOconv(e, ...) en TU
dynConcatSz(e, &ctxPdf->mPdf, ") >> endobj\r\n", DYN_LGNONE);
setXref(e, ctxPdf);
// liste des pages
cpt = nb_obj_entete;
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNbPage; i++)
if(ctxPdf->mNbPage > 0)
{
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
// liste des pages
cpt = nb_obj_entete;
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNbPage; i++)
{
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
} /* si nb page pas connu, sera mis a la fin */
/* liste des fontes, prendre celles utilisees */
cpt = nb_obj_fixe;
cpt = ctxPdf->mNbObjFixe;
for(i = 1, nbp = 0; i <= PDFFONT_NB; i++)
{
dynField(e, &ctxPdf->mFont, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
@@ -471,6 +532,9 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
dynConcatSz(e, &ctxPdf->mPdf," /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding >> >> endobj\r\n", DYN_LGNONE);
}
}
if(nbp != nb_font)
return FALSE;
ctxPdf->mNbFont = nbp;
/* liste des images */
for(i = 1; i <= nb_img; i++)
{
@@ -487,15 +551,12 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mXref, " 0 0 ", DYN_LGNONE);
dynConcat(e, &ctxPdf->mXref, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf," /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /LZWDecode /Length ", DYN_LGNONE); // TODO remplacer /ASCIIHexDecode par /LZWDecode
dynConcatSz(e, &ctxPdf->mPdf," /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /LZWDecode /Length ", DYN_LGNONE); // /LZWDecode remplace /ASCIIHexDecode
dynField(e, &ctxPdf->mImg, &ctxPdf->mTmp1, i, 3, cFM, cVM, 1); // vm1 = larg (w) VM2 = haut (h) VM3 = bitmap 32bpp hexa RGBRGBRGBRGB
convertHexaRGBToBinLzw(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mTmp2.mLg, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " >>\r\nstream\r\n", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
//dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mTmp1.mLg, FALSE, 0), DYN_LGNONE);
//dynConcatSz(e, &ctxPdf->mPdf, " >>\r\nstream\r\n", DYN_LGNONE);
//dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf,"\r\nendstream\r\nendobj\r\n", DYN_LGNONE);
}
/* definition de chaque page */
@@ -512,7 +573,7 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
dynConcatSz(e, &ctxPdf->mPdf, "/F", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + nb_obj_fixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
@@ -523,7 +584,7 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
dynConcatSz(e, &ctxPdf->mPdf, "/Img", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + nb_obj_fixe + nbp, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe + nbp, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R", DYN_LGNONE);
if(j == nb_img)
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
@@ -538,6 +599,21 @@ WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_pa
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf)
{
long i, nb; /* nb xref */
if(ctxPdf->mNbPage == 0)
{
majXref(e, ctxPdf, 3);
// liste des pages
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNumPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNumPage; i++)
{
dynField(e, &ctxPdf->mInfoPage, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
}
setXref(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, "xref\r\n0 ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj + 1, FALSE, DYN_NONE), DYN_LGNONE);
@@ -568,12 +644,45 @@ WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf)
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
{
int cr = TRUE;
int cr = TRUE, j;
/* compression = 0 : pas de compression LZW */
/* 1 : compression LZW en binaire */
setXref(e, ctxPdf);
ctxPdf->mNbObj++;
ctxPdf->mNumPage++;
if(ctxPdf->mNbPage == 0)
{
setXref(e, ctxPdf);
dynStoreNumber(e, &ctxPdf->mInfoPage, ctxPdf->mNumPage, DYN_NONE, ctxPdf->mNbObj, cFM, DYN_NONE); /* num objet declaration page (pas le contenu) */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj++, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Type /Page /Parent 3 0 R /MediaBox [ 0 0 ", DYN_LGNONE);
fmt2(e, &ctxPdf->mPdf, ctxPdf->mLarg, ctxPdf->mHaut);
dynConcatSz(e, &ctxPdf->mPdf," ] /Resources << /Font << ", DYN_LGNONE);
for(j = 1; j <= ctxPdf->mNbFont; j++)
{
dynConcatSz(e, &ctxPdf->mPdf, "/F", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
for(j = 1; j <= ctxPdf->mNbImg; j++)
{
if(j == 1)
dynConcatSz(e, &ctxPdf->mPdf, "/XObject << ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, "/Img", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe + ctxPdf->mNbFont, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R", DYN_LGNONE);
if(j == ctxPdf->mNbImg)
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> /Contents ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R >> endobj\r\n", DYN_LGNONE);
}
setXref(e, ctxPdf);
/* ajout du code "PDF" directement */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Length ", DYN_LGNONE);
@@ -586,10 +695,8 @@ WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
}
else
{
// compression LZW du stream de la page
//ctxPdf->mCtxLzw.compress_do(0, (unsigned char *)ctxPdf->mPage.mPtr, ctxPdf->mPage.mLg); // verif
/* compression LZW du stream de la page */
setLzw(e, &ctxPdf->mPage, &ctxPdf->mCtxLzw, 0);
//ctxPdf->mPage = ctxPdf->mLzw.getCode(); // verif
/* */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mPage.mLg, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " /Filter /LZWDecode >>\r\nstream\r\n", DYN_LGNONE);
@@ -675,6 +782,33 @@ WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, lon
return cr;
}
WAPIDECL int setCab128(env * e, modContextPdf * ctxPdf, Dynamic * data, long x, long y, long h)
{
long cpt_char, code, x_orig = x, checksum = 104; /* StartB */
code = 104; /* StartB */
graphCab128(e, ctxPdf, code, &x, y, h);
for(cpt_char = 0; cpt_char < data->mLg; cpt_char++)
{
code = (long)(data->ptr[cpt_char]);
if(code > 31 && code < 127)
{
code -= 32;
graphCab128(e, ctxPdf, code, &x, y, h);
checksum += code * (cpt_char + 1);
}
/* sinon, caractere non gere en Code128 : RAF */
}
code = checksum % 103;
graphCab128(e, ctxPdf, code, &x, y, h);
code = 106; /* Stop */
graphCab128(e, ctxPdf, code, &x, y, h);
/* */
dynLet(e, &ctxPdf->mTmp3, "*", 1);
dynConcat(e, &ctxPdf->mTmp3, data);
dynConcatSz(e, &ctxPdf->mTmp3, "*", 1);
return setPdfText(e, ctxPdf, x_orig, y - h/2, x - x_orig, 80, 1, 8, RGB(0,0,0), &ctxPdf->mTmp3); // utilise la premiere fonte declaree utilisee (1), taille 8, en noir
}
WAPIDECL int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
{
int cr = TRUE;
@@ -1005,7 +1139,7 @@ WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic *
}
dynConcatSz(e, &ctxPdf->mPage, "ET\r\n", DYN_LGNONE);
//
if( ! setPdfPage(e, ctxPdf, 1)) // compression forcee, mettre un param ?
if( ! setPdfPage(e, ctxPdf, 1)) // avec compression
return FALSE;
}
return endPdf(e, ctxPdf);
+89 -62
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,7 +27,9 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
enum {
RAND_STATE_COUNT = 624,
RAND_PERIOD = 397
@@ -62,7 +64,7 @@ static void randomTwist(modEtat * etat)
etat->index = 0;
}
ent32 randomGenerate(modEtat * etat)
static ent32 randomGenerate(modEtat * etat)
{
if (etat->index >= RAND_STATE_COUNT)
randomTwist(etat);
@@ -75,16 +77,20 @@ ent32 randomGenerate(modEtat * etat)
return y & 0xFFFFFFFF;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -93,111 +99,132 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
randomInit(p_etat, time(NULL));
//
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
randomInit(p_etat, time(NULL));
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "setSeed", 7))
{
if(param1 == NULL)
/* get param in the right order */
var * paramSeedValue = getParam(e, "seedValue", 9);
if(paramSeedValue == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
else if(paramSeedValue->type != VAR_NUMBER && paramSeedValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
randomInit(p_etat, (ent32)((param1->num / NUM_FACTEUR) & 0xFFFFFFFF));
number seed;
if(var_conv_num(e, paramSeedValue, &seed))
randomInit(p_etat, (ent32)((seed / NUM_FACTEUR) & 0xFFFFFFFF));
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
/* get param in the right order */
var * paramNextRandomNumber = getParam(e, "nextRandomNumber", 16);
if(paramNextRandomNumber == NULL)
exc = EX_MODPARAM;
else
{
param1->num = (((ent64)(randomGenerate(p_etat))) * NUM_FACTEUR);
if(paramNextRandomNumber->type != VAR_NUMBER)
var_let(e, paramNextRandomNumber, &e->int_number, FALSE, FALSE);
paramNextRandomNumber->num = (((ent64)(randomGenerate(p_etat))) * NUM_FACTEUR);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+9
View File
@@ -393,3 +393,12 @@ WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dyna
*ficLine = lineNumber - dynFieldAsNumber(e, meta, indice + META_GLOBAL_LN, pos, cFM, cVM) + dynFieldAsNumber(e, meta, indice + META_LOCAL_LN, pos, cFM, cVM);
dynField(e, meta, fileFound, indice + META_FILENAME, pos, cFM, cVM, 1);
}
WAPIDECL void GetTempDirectory(env * e, Dynamic * dir)
{
#ifdef WINLIB
dynLet(e, dir, "C:\\Temp\\", DYN_LGNONE);
#else
dynLet(e, dir, "/tmp/", 5);
#endif
}
+2
View File
@@ -40,5 +40,7 @@ WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dyn
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine);
WAPIDECL void GetTempDirectory(env * e, Dynamic * dir);
/* ********************************************** */
#endif
+18 -8
View File
@@ -27,9 +27,13 @@
/* codes a passer a la fonction setError */
enum {
WSECURESOCKET_MEM_ERROR = -2,
WSECURESOCKET_ERROR = -1,
WSECURESOCKET_OK = 0,
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 {
@@ -38,16 +42,22 @@ typedef struct {
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 void initSecureSock(env * e, modContextSecureSocket * ctx);
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); /* secure socket from server accept */
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server);
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, SSL * ssl, var * data, long timeoutMs);
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, SSL * ssl, var * data);
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);
+232 -167
View File
@@ -51,27 +51,42 @@ typedef struct {
modContextSecureSocket ctxSecureSock;
} modEtat;
enum {
EXMOD_SECURESOCK_SERVER_PORT_NUM = 1,
EXMOD_SECURESOCK_SERVER_PORT_INVALID = 2,
EXMOD_SECURESOCK_NEW = 3,
EXMOD_SECURESOCK_SETSERVER = 4,
EXMOD_SECURESOCK_CONNECT = 5,
EXMOD_SECURESOCK_WAIT = 6,
EXMOD_SECURESOCK_ACCEPT = 7,
EXMOD_SECURESOCK_READ = 8,
EXMOD_SECURESOCK_WRITE = 9,
EXMOD_SECURESOCK_SECURESERVER = 10,
EXMOD_SECURESOCK_SECURECLIENT = 11,
EXMOD_SECURESOCK_SETCERTIFICATE = 12
};
#define MOD_VERSION 1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
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 */
@@ -82,122 +97,125 @@ 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
// fonction createServer, arret
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
initSecureSock(e, &p_etat->ctxSecureSock);
// 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))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
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))
{
// renvoie la version du module/plugins
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// 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);
/* extend error */
if(param2 != NULL)
if(param2->type == VAR_NUMBER)
param2->num = (ent64)(NUM_FACTEUR * p_etat->ctxSecureSock.ctxSock.err);
}
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "server", 6))
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
return (exc = EX_MODETAT);
else if(param1 == NULL)
/* 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(param1->type != VAR_NUMBER && param1->type != VAR_DYNAMIC)
else if((paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC) ||
paramCertificate->type != VAR_DYNAMIC || paramPrivateKey->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// param<1> = numero de port
/* cree un point d'entree serveur securise SSL/TLS */
number port;
if( ! var_conv_num(e, param1, &port))
exc = setError(p_etat, EXMOD_SECURESOCK_SERVER_PORT_NUM);
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) == WSOCKET_OK)
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)) == WSOCKET_OK)
if(SocketSetServer(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.sock, (int)(port / NUM_FACTEUR), NULL) == WSOCKET_OK)
{
// TODO Certificats
if(SetPemCertificate(e, &p_etat->ctxSecureSock, NULL, NULL) == WSECURESOCKET_OK)
if(SetPemCertificate(e, &p_etat->ctxSecureSock, paramCertificate, paramPrivateKey) == WSECURESOCKET_OK)
{
if(SecureSocketServer(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock) == WSECURESOCKET_OK)
{
exc = OK;
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_SECURESERVER);
}
exc = OK; /* un seul serveur en ecoute ! */
}
else
exc = setError(p_etat, EXMOD_SECURESOCK_SETCERTIFICATE);
@@ -217,161 +235,208 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "connect", 7))
{
/* connexion a un serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
/* 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(param1->type != VAR_DYNAMIC || (param2->type != VAR_NUMBER && param2->type != VAR_DYNAMIC) || param3->type != VAR_NUMBER)
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
{
// param1 = host (nom ou ip)
// param2 = port
// param3 = socket cliente en retour
number port;
if( ! var_conv_num(e, param2, &port))
exc = setError(p_etat, EXMOD_SECURESOCK_SERVER_PORT_NUM);
/* 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) == WSOCKET_OK)
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), param1) == WSOCKET_OK)
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, param1) == WSECURESOCKET_OK)
if(SecureSocketClient(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock, paramHost, timeout * 1000 / NUM_FACTEUR) == WSECURESOCKET_OK)
{
param3->num = p_etat->ctxSecureSock.ctxSock.sock; /* (sock * NUM_FACTEUR) ? */
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, "stopServer", 10))
else if(modFnIs(e, "setCACert", 9))
{
/* arret serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
/* 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
{
// A REVOIR
FreeSocket(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock);
p_etat->ctxSecureSock.ctxSock.servSock = INVALID_SOCKET;
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))
{
/* arret connexion cliente */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
if(paramSocket == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
else if(paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// A REVOIR
FreeSocket(e, &p_etat->ctxSecureSock.ctxSock, param1->num);
/* 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))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
/* get param in the right order */
var * paramTimeout = getParam(e, "timeout", 7);
var * paramClientSock = getParam(e, "clientSock", 10);
if(paramTimeout == NULL || paramClientSock == NULL)
exc = EX_MODPARAM;
else if(paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// attend une activite sur la socket serveur et si oui cree une nouvelle socket, timeout en secondes
long cr = WaitOneSocketForRead(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock, param1->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SECURESOCK_WAIT);
else if(cr == 0)
param2->num = NUM_MOINSUN; /* => timeout, RAS */
number timeout;
if( ! var_conv_num(e, paramTimeout, &timeout) )
exc = EX_MODPARAM;
else
{
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSecureSock.ctxSock) == WSOCKET_OK)
{
param2->num = p_etat->ctxSecureSock.ctxSock.sock;
}
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
exc = setError(p_etat, EXMOD_SECURESOCK_ACCEPT);
{
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))
{
/* lecture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_NUMBER)
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
else
{
/* lire par paquets de longueur fixe et s'arreter des que plus rien a lire
lecture par paquets de <pas> octets
param1 = socket, param2 = chaine lue, param3 = timeout en secondes
*/
long cr = WaitOneSocketForRead(e, &p_etat->ctxSecureSock.ctxSock, param1->num, param3->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SECURESOCK_WAIT);
else if(cr == 0)
dynSetLen(e, param2, 0); /* => timeout, RAS */
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) )
{
/* socket a recu des donnees */
if(ReadSocket(e, &p_etat->ctxSecureSock.ctxSock, param1->num, param2, param3->num * 1000 / NUM_FACTEUR) != WSOCKET_OK)
/* traiter le cas WSOCKET_END_CONNECT : erreur ? (fin cnx) */
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))
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC)
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
else
{
/* param1 = socket, param2 = chaine a ecrire */
if(WriteSecureSocket(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.sslClient, param2) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SECURESOCK_WRITE);
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
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
+295 -54
View File
@@ -84,47 +84,182 @@
=== 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
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 void initSecureSock(env * e, modContextSecureSocket * ctx)
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, NULL);
/* Charger les autorités de confiance */
if (!SSL_CTX_load_verify_locations(ctx->clientSecureCtx, "/etc/ssl/certs/ca-certificates.crt", NULL))
; // erreur : quid ?
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 */
/* */
ctx->packet = 16000;
return cr;
}
WAPIDECL void freeSecureSock(env * e, modContextSecureSocket * ctx)
{
/* SSL_shutdown(ctx->sslXXX) ? */
SSL_free(ctx->sslClient);
SSL_free(ctx->sslServer);
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)
@@ -134,60 +269,166 @@ WAPIDECL long SetPemCertificate(env * e, modContextSecureSocket * ctx, Dynamic
return WSECURESOCKET_OK;
}
WAPIDECL long SecureSocketServer(env * e, modContextSecureSocket * ctx, Socket sock)
WAPIDECL long SecureSocketServer(env * e, modContextSecureSocket * ctx, Socket sock, long timeoutMs)
{
/* secure socket from server accept */
ctx->sslServer = SSL_new(ctx->serverSecureCtx);
SetBlocking(sock, WSOCKET_NONBLOCKING);
ctx->sslServer = SSL_new(ctx->serverSecureCtx);
SSL_set_fd(ctx->sslServer, sock);
if(SSL_accept(ctx->sslServer) <= 0)
return WSECURESOCKET_ERROR;
else
return WSECURESOCKET_OK;
}
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server)
{
/* secure socket connected to a server */
ctx->sslClient = SSL_new(ctx->clientSecureCtx);
SSL_set_fd(ctx->sslClient, sock);
if(SSL_connect(ctx->sslClient) <= 0)
return WSECURESOCKET_ERROR;
else
{
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, SSL * ssl, var * data, long timeoutMs)
{
int packetLg = ctx->packet;
AddSsl(e, ctx, ctx->sslServer, sock); /* TODO array */
/* */
int ret;
for(;;)
{
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
if((ret = processSSLresponse(e, ctx, ctx->sslServer, SSL_accept(ctx->sslServer))) < 0)
{
return WSECURESOCKET_MEM_ERROR; // erreur memoire
}
int nbRead = SSL_read(ssl, data->mPtr + data->mLg, packetLg);
if(nbRead < 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;
dynSetLen(e, data, data->mLg + nbRead);
if(nbRead < packetLg)
return WSECURESOCKET_OK;
}
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, SSL * ssl, var * data)
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs)
{
SSL_write(ssl, data->mPtr, data->mLg);
SSL * ssl;
if(!(ssl = GetSsl(e, ctx, sock))) return WSECURESOCKET_ERROR; /* TODO array */
/* */
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr <= 0)
return WSECURESOCKET_ERROR; /* timeout = error */
/* */
ent64s dejaLu = 0;
int nbWrite;
for(;;)
{
if((nbWrite = processSSLresponse(e, ctx, ssl, SSL_write(ssl, data->mPtr + dejaLu, data->mLg - dejaLu))) < 0)
{
if(nbWrite == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr > 0)
continue;
}
if(nbWrite == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr > 0)
continue;
}
return WSECURESOCKET_ERROR;
}
else
{
if(nbWrite >= data->mLg - dejaLu)
break; /* data ok */
/* tout n'a pas ete ecrit : continuer */
dejaLu += nbWrite;
}
}
return WSECURESOCKET_OK;
}
-3
View File
@@ -68,6 +68,3 @@ WAPIDECL void initShm(env * e, modContextShm * ctx);
WAPIDECL void freeShm(env * e, modContextShm * ctx);
WAPIDECL long readShm(env * e, modContextShm * ctx);
WAPIDECL long writeShm(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx);
+106 -74
View File
@@ -27,23 +27,34 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
/* ============================================================================================= */
#include "shm.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextShm cs;
} modEtat;
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_PROCESSNAME_TOOLONG = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Name of process too long (from 1 to 23)"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -52,130 +63,151 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
var * prog;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_PROG), &prog);
// maj ctx avec _prog et taille
*((ent64 *)(p_etat->cs.nom)) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 1) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 2) = 0;
if(prog && prog->type == VAR_DYNAMIC && prog->mLg < 24)
strncpy(p_etat->cs.nom, prog->mPtr, prog->mLg);
p_etat->cs.taille = 4000;
//
initShm(e, &p_etat->cs);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
var * prog;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_PROG), &prog);
// maj ctx avec _prog et taille
*((ent64 *)(p_etat->cs.nom)) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 1) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 2) = 0;
if(prog && prog->type == VAR_DYNAMIC && prog->mLg < 24)
strncpy(p_etat->cs.nom, prog->mPtr, prog->mLg);
p_etat->cs.taille = 4000;
//
initShm(e, &p_etat->cs);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeShm(e, &p_etat->cs);
//*** FIN du code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramContent = getParam(e, "content", 7);
if(paramContent == NULL)
exc = EX_MODPARAM;
else
{
p_etat->cs.message = param1;
exc = setError(p_etat, readShm(e, &p_etat->cs));
// param1 vide si rien a lire
if(paramContent->type != VAR_DYNAMIC)
var_let(e, paramContent, &e->int_dynamic, FALSE, FALSE);
p_etat->cs.message = paramContent;
exc = setError(p_etat, readShm(e, &p_etat->cs)); // paramContent renvoye a vide si rien a lire
}
}
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramTextMessage = getParam(e, "textMessage", 11);
var * paramProcessName = getParam(e, "processName", 11);
if(paramTextMessage == NULL || paramProcessName == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramTextMessage->type != VAR_DYNAMIC || paramProcessName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
*((ent64 *)(p_etat->cs.desti)) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 1) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 2) = 0;
if(param1->mLg < 24)
strncpy(p_etat->cs.desti, param1->mPtr, param1->mLg);
p_etat->cs.message = param2;
exc = setError(p_etat, writeShm(e, &p_etat->cs));
if(paramProcessName->mLg > 0 && paramProcessName->mLg < 24)
{
strncpy(p_etat->cs.desti, paramProcessName->mPtr, paramProcessName->mLg);
p_etat->cs.message = paramTextMessage;
exc = setError(p_etat, writeShm(e, &p_etat->cs));
}
else
exc = setError(p_etat, EXMOD_PROCESSNAME_TOOLONG);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
/* **************************************************************************************************** */
+1 -102
View File
@@ -261,108 +261,7 @@ WAPIDECL long writeShm(env * e, modContextShm * ctx)
return e->exception;
}
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, ctx->message->lg + sizeLg, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// ne liberer que le ptr sous unix
shmdt(data);
#else
// la cle est directement le destinataire
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->message->lg + sizeLg, ctx->desti); // attention au \0 de fin
if( ! handle)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// dupliquer le HANDLE sur le mapping
HANDLE dup = NULL;
if( ! DuplicateHandle(GetCurrentProcess(), handle, ctx->newProcess, &dup, 0, FALSE, DUPLICATE_SAME_ACCESS))// FALSE : le handle dupliqué n’a pas besoin d’être héritable
e->exception = EXMOD_BUFFER_WRITE;
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, 0, 0); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// ne liberer que le ptr sous unix
shmdt(data);
shmctl(handle, IPC_RMID, NULL);
#else
// lire le pointeur, a partir du handle lu de la ligne de commande
HANDLE handle = ctx->newProcess;
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
/* utilite ? */
#ifndef WINLIB
WAPIDECL int OpenLock(env * e, const char * name)
{
+13 -4
View File
@@ -30,6 +30,7 @@
#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>
@@ -42,6 +43,7 @@
#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;
@@ -53,11 +55,15 @@ enum {
WSOCKET_MEM_ERROR = -2,
WSOCKET_ERROR = -1,
WSOCKET_OK = 0,
WSOCKET_LISTEN_MAX = 10
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
@@ -73,10 +79,11 @@ typedef struct {
WAPIDECL void initSock(env * e, modContextSocket * ctx);
WAPIDECL void freeSock(env * e, modContextSocket * ctx);
WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx);
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port);
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 * server);
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);
@@ -89,3 +96,5 @@ 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);
+374 -164
View File
@@ -25,32 +25,39 @@
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "rep.h"
#include <signal.h>
#include <errno.h>
#ifdef UNIX
#ifdef WINLIB
#include "winsock2.h"
#include "windows.h"
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#else
#include "winsock2.h"
#include "windows.h"
#include <sys/utsname.h>
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "sock.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
modContextSocket ctxSock;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_SOCK_SERVER_PORT_NUM = 1,
EXMOD_SOCK_SERVER_PORT_INVALID = 2,
@@ -60,15 +67,31 @@ enum {
EXMOD_SOCK_WAIT = 6,
EXMOD_SOCK_ACCEPT = 7,
EXMOD_SOCK_READ = 8,
EXMOD_SOCK_WRITE = 9
EXMOD_SOCK_WRITE = 9,
EXMOD_SOCK_NOTNUM = 10,
EXMOD_SOCK_GETHOST = 11,
EXMOD_SOCK_GETNAME = 12,
EXMOD_NB = 12
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Port number expected as number",
"Port number invalid",
"New socket error",
"Listen socket on port error",
"Connect socket error", // 5
"Waiting for socket error",
"Accept socket error",
"Read socket error",
"Write socket error",
"Socket expected as number", // 10
"Get host address error",
"Get host name error"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -79,161 +102,158 @@ 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
// fonction createServer, arret
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
initSock(e, &p_etat->ctxSock);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initSock(e, &p_etat->ctxSock);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
//*** code specifique ici
freeSock(e, &p_etat->ctxSock);
//***
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// 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);
/* extend error */
if(param2 != NULL)
if(param2->type == VAR_NUMBER)
param2->num = (ent64)(NUM_FACTEUR * p_etat->ctxSock.err);
}
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "server", 6))
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
return (exc = EX_MODETAT);
else if(param1 == NULL)
/* get param in the right order */
var * paramPortNumber = getParam(e, "portNumber", 10);
/* TODO socket unix locale (pas en mode secure) */
if(paramPortNumber == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER && param1->type != VAR_DYNAMIC)
else if(paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// param<1> = numero de port
/* cree un point d'entree serveur */
number port;
if( ! var_conv_num(e, param1, &port))
if( ! var_conv_num(e, paramPortNumber, &port))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM);
else if(port < 1024 * NUM_FACTEUR || port > 65535 * NUM_FACTEUR)
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_INVALID); /* en dessous de 1024, necessite des autorisations speciales, non gere ici */
else
{
if(NewSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
if(NewSocket(e, &p_etat->ctxSock, FALSE) == WSOCKET_OK)
{
if(SocketSetServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR)) == WSOCKET_OK)
{
exc = OK;
}
else
{
if(SocketSetServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), NULL) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SOCK_SETSERVER);
}
}
else
{
exc = setError(p_etat, EXMOD_SOCK_NEW);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "connect", 7))
{
/* connexion a un serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramPortNumber = getParam(e, "portNumber", 10);
var * paramSocket = getParam(e, "socket", 6);
/* socket unix locale (pas en mode secure) */
if(paramHost == NULL || paramPortNumber == NULL || paramSocket == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || (param2->type != VAR_NUMBER && param2->type != VAR_DYNAMIC) || param3->type != VAR_NUMBER)
else if(paramHost->type != VAR_DYNAMIC || (paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
// param1 = host (nom ou ip)
// param2 = port
// param3 = socket cliente en retour
/* connexion a un serveur */
number port;
if( ! var_conv_num(e, param2, &port))
if( ! var_conv_num(e, paramPortNumber, &port))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM);
else
{
if(NewSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
if(NewSocket(e, &p_etat->ctxSock, FALSE) == WSOCKET_OK)
{
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), param1) == WSOCKET_OK)
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), NULL, paramHost) == WSOCKET_OK)
{
param3->num = p_etat->ctxSock.sock; /* (sock * NUM_FACTEUR) ? */
exc = 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);
}
}
}
}
@@ -241,113 +261,303 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
else if(modFnIs(e, "stopServer", 10))
{
/* arret serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.servSock);
p_etat->ctxSock.servSock = INVALID_SOCKET;
}
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.servSock);
p_etat->ctxSock.servSock = INVALID_SOCKET;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stop", 4))
{
/* arret connexion cliente */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
if(paramSocket == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
else if(paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FreeSocket(e, &p_etat->ctxSock, param1->num);
/* 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))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
/* get param in the right order */
var * paramTimeout = getParam(e, "timeout", 7);
var * paramClientSock = getParam(e, "clientSock", 10);
if(paramTimeout == NULL || paramClientSock == NULL)
exc = EX_MODPARAM;
else if(paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// 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, param1->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
param2->num = NUM_MOINSUN; /* => timeout, RAS */
number timeout;
if( ! var_conv_num(e, paramTimeout, &timeout) )
exc = EX_MODPARAM;
else
{
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
param2->num = p_etat->ctxSock.sock;
}
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
exc = setError(p_etat, EXMOD_SOCK_ACCEPT);
{
/* 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))
{
/* lecture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_NUMBER)
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
else
{
/* lire par paquets de longueur fixe et s'arreter des que plus rien a lire
lecture par paquets de <pas> octets
param1 = socket, param2 = chaine lue, param3 = timeout en secondes
*/
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, param1->num, param3->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
dynSetLen(e, param2, 0); /* => timeout, RAS */
else
number socket, timeout;
if( var_conv_num(e, paramSocket, &socket) && var_conv_num(e, paramTimeout, &timeout) )
{
/* socket a recu des donnees */
if(ReadSocket(e, &p_etat->ctxSock, param1->num, param2, param3->num * 1000 / NUM_FACTEUR) != WSOCKET_OK)
/* traiter le cas WSOCKET_END_CONNECT : erreur ? (fin cnx) */
exc = setError(p_etat, EXMOD_SOCK_READ);
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;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
if(paramSocket == NULL || paramData == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC)
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
else
{
/* param1 = socket, param2 = chaine a ecrire */
if(WriteSocket(e, &p_etat->ctxSock, param1->num, param2) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SOCK_WRITE);
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(modFnIs(e, "export", 6))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramPid = getParam(e, "pid", 3);
/* envoi d'une socket a un autre process via son pid, par socket unix locale (non secu) */
if(paramSocket == NULL || paramPid == NULL)
exc = EX_MODPARAM;
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || (paramPid->type != VAR_NUMBER && paramPid->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
number socket, pid;
if( ! var_conv_num(e, paramSocket, &socket) || ! var_conv_num(e, paramPid, &pid))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM); // TODO
else
{
if(NewSocket(e, &p_etat->ctxSock, TRUE) == WSOCKET_OK)
{
GetTempDirectory(e, &e->tmp_dynamic);
dynConcatSz(e, &e->tmp_dynamic, "wsocket_", 8);
dynConcatNumber(e, &e->tmp_dynamic, pid);
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, 0, &e->tmp_dynamic, NULL) == WSOCKET_OK)
{
if(SendSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, socket, pid) == OK)
{
if(ReadSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, &e->tmp_dynamic, 1000) == WSOCKET_OK) /* delai 1 sec. */
{
/* verifier si les donnes lues sont egales a "OK" */
/* socket bien recue par l'autre process : fermer celle ici */
FreeSocket(e, &p_etat->ctxSock, socket);
}
else
exc = setError(p_etat, EXMOD_SOCK_READ); // TODO
}
else
exc = setError(p_etat, EXMOD_SOCK_READ); // TODO
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock);
}
else
exc = setError(p_etat, EXMOD_SOCK_CONNECT); // TODO
}
else
exc = setError(p_etat, EXMOD_SOCK_NEW); // TODO
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "import", 6))
{
/* 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
{
if(paramSocket->type != VAR_NUMBER)
var_let(e, paramSocket, &e->int_number, FALSE, FALSE);
paramSocket->num = NUM_MOINSUN;
/* */
if(NewSocket(e, &p_etat->ctxSock, TRUE) == WSOCKET_OK)
{
GetTempDirectory(e, &e->tmp_dynamic);
dynConcatSz(e, &e->tmp_dynamic, "wsocket_", 8);
dynConcatNumber(e, &e->tmp_dynamic, getpid());
if(SocketSetServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, 0, &e->tmp_dynamic) == WSOCKET_OK)
{
// couper ici et faire 2 fn : une qui init la socket unix locale, et une qui ecoute et lit une socket
// attend une activite sur la socket serveur et si oui cree une nouvelle socket, timeout 1 seconde en ms
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, p_etat->ctxSock.servSock, 1000);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
; /* => timeout, RAS */
else
{
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
Socket socket;
if(ReceiveSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, &socket) == OK)
{
dynLet(e, &e->tmp_dynamic, "OK", 2);
if(WriteSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock, &e->tmp_dynamic) == WSOCKET_OK)
{
/* socket bien recue de l'autre process */
paramSocket->num = socket;
}
else
exc = setError(p_etat, EXMOD_SOCK_WRITE); // TODO
}
else
exc = setError(p_etat, EXMOD_SOCK_READ); // TODO
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.sock);
}
else
exc = setError(p_etat, EXMOD_SOCK_ACCEPT);
}
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.servSock); // idem 'stopserver', a separer
}
else
exc = setError(p_etat, EXMOD_SOCK_CONNECT); // TODO
}
else
exc = setError(p_etat, EXMOD_SOCK_NEW); // TODO
}
}
/* ============================================================================================= */
else
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+299 -75
View File
@@ -43,15 +43,38 @@
/* ---------------------------------------------------- */
/* ****** 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;
ctx->packet = 16000; /* parametrable par une fonction ? */
ctx->nbSocket = 0;
//
#ifdef WINLIB
@@ -63,6 +86,8 @@ WAPIDECL void initSock(env * e, modContextSocket * ctx)
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++)
{
@@ -75,13 +100,26 @@ WAPIDECL void freeSock(env * e, modContextSocket * ctx)
#endif
}
dynFree(e, &ctx->listSocket);
dynFree(e, &ctx->localSocket);
#ifdef WINLIB
WSACleanup();
#endif
}
WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx)
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);
@@ -94,51 +132,77 @@ WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx)
struct linger l_s; /* Structure pour setsockopt */
Socket sock;
/* */
#ifndef WINLIB
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
#else
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
#endif
if(local)
{
ctx->err = GetSocketError();
return WSOCKET_ERROR;
/* 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
//#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 */
/* */
/* 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
SetBlocking(sock, WSOCKET_NONBLOCKING);
/* */
if(!local) /* options inutiles en mode socket unix locale */
{
ctx->err = GetSocketError();
/* 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
close(sock);
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
closesocket(sock);
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
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;
{
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))) ;
@@ -171,18 +235,47 @@ WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx)
return WSOCKET_OK;
}
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port)
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port, var * localPath)
{
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);
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, (struct sockaddr *)&addr, sizeof(addr)) < 0)
if(bind(sock, sa, sofsa) < 0)
#else
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
if(bind(sock, sa, sofsa) == SOCKET_ERROR)
#endif
{
ctx->err = GetSocketError();
@@ -191,6 +284,7 @@ WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int
#else
closesocket(sock);
#endif
DeleteLocalSocketFile(e, ctx);
return WSOCKET_ERROR;
}
#ifndef WINLIB
@@ -205,6 +299,7 @@ WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int
#else
closesocket(sock);
#endif
DeleteLocalSocketFile(e, ctx);
return WSOCKET_ERROR;
}
if(AddSocket(e, ctx, sock) == WSOCKET_OK)
@@ -213,7 +308,15 @@ WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int
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)
@@ -231,7 +334,14 @@ WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx)
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
{
@@ -240,39 +350,59 @@ WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx)
}
}
WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * server)
WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * localPath, var * server)
{
struct sockaddr_in addr;
struct hostent * serv;
//
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
#ifndef WINLIB
if(inet_aton(server->mPtr, &(addr.sin_addr)) == 0)
#else
if(InetPton(AF_INET, server->mPtr, &addr.sin_addr) != 1)
#endif
struct sockaddr * sa;
int sofsa;
/* utilise soit 'localPath' soit 'server' 'port' */
if(localPath)
{
// no ip v4 format, search for name
if((serv = gethostbyname(server->mPtr)) == NULL)
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))
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
dynSetLen(e, &ctx->localSocket, 0);
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);
strcpy(addr.sun_path, ctx->localSocket.mPtr); /* la gestion du fichier socket local est laisse a la gestion du socket serveur en ecoute */
sa = (struct sockaddr *)&addr;
sofsa = sizeof(addr);
}
/* laisser en bloquant (tout le temps) et gerer la pseudo erreur
"EINPROGRESS/EWOULDBLOCK" => attendre ici que socket ok en ecriture
*/
int ret = connect(sock, (struct sockaddr *)&addr, 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)
{
@@ -327,6 +457,91 @@ WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock
return WSOCKET_OK;
}
WAPIDECL long SendSocket(env * e, modContextSocket * ctx, Socket sock, Socket socketToSend, number pid)
{
/* send socket using AF_UNIX local socket */
#ifndef WINLIB
struct msghdr msg = {0};
char buffer[CMSG_SPACE(sizeof(int))];
memset(buffer, 0, sizeof(buffer));
struct iovec io = {
.iov_base = (void *)"X", /* peu importe... */
.iov_len = 1
};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buffer;
msg.msg_controllen = sizeof(buffer);
struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg);
if(cmsg == NULL)
return -1;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsg), &socketToSend, sizeof(socketToSend));
if(sendmsg(sock, &msg, 0) < 0)
return -1;
else
return OK;
/* */
#else
WSAPROTOCOL_INFO info = {0};
if(WSADuplicateSocket(socketToSend, pid, &info) == SOCKET_ERROR)
return -1;
var * v = &e->tmp_dynamic; // verifier que v assez grand pour info
if(dynCtrl(e, v, sizeof(info), FALSE))
return -1;
memcpy(v->ptr, &info, sizeof(info));
v->mLg = sizeof(info);
if(WriteSocket(e, ctx, sock, v) != WSOCKET_OK)
return -1;
else
return OK;
#endif
}
WAPIDECL long ReceiveSocket(env * e, modContextSocket * ctx, Socket sock, Socket * socketReceived)
{
/* receive socket from AF_UNIX local socket */
#ifndef WINLIB
struct msghdr msg = {0};
char buffer[CMSG_SPACE(sizeof(int))];
memset(buffer, 0, sizeof(buffer));
struct iovec io = {
.iov_base = (void *)"X", /* peu importe... */
.iov_len = sizeof(1)
};
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = buffer;
msg.msg_controllen = sizeof(buffer);
if(recvmsg(sock, &msg, 0) <= 0)
return -1;
if(msg.msg_flags & MSG_CTRUNC)
return -1;
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if(cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS || cmsg->cmsg_len < CMSG_LEN(sizeof(int)))
return -1; /* pas de socket valide recue */
memcpy(socketReceived, CMSG_DATA(cmsg), sizeof(*socketReceived));
return OK;
/* */
#else
var * v = &e->tmp_dynamic;
dynSetLen(e, v, 0);
if(ReadSocket(e, ctx, sock, v, 1000) != WSOCKET_OK) // 1 sec.
return -1;
WSAPROTOCOL_INFO info = {0};
if(v->mLg != sizeof(info))
return -1;
memcpy(&info, v->ptr, sizeof(info));
*socketReceived = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &info, 0, 0);
if(*socketReceived == INVALID_SOCKET)
return -1;
else
return OK;
#endif
}
WAPIDECL long AddSocket(env * e, modContextSocket * ctx, Socket sock)
{
#ifndef WINLIB
@@ -387,7 +602,10 @@ 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
@@ -405,7 +623,10 @@ 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
@@ -426,6 +647,7 @@ WAPIDECL long WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock,
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())
}
@@ -452,6 +674,7 @@ WAPIDECL long WaitOneSocketForWrite(env * e, modContextSocket * ctx, Socket sock
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())
}
@@ -472,7 +695,7 @@ WAPIDECL long WaitOneSocketForWrite(env * e, modContextSocket * ctx, Socket sock
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);
@@ -480,6 +703,8 @@ WAPIDECL void FreeSocket(env * e, modContextSocket * ctx, Socket sock)
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);
}
@@ -559,7 +784,6 @@ WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * da
/* */
for(;;)
{
// TODO ajouter WaitOneSocketForWrite()
int cr = WaitOneSocketForWrite(e, ctx, sock, timeoutMs);
if(cr < 0)
{
+79
View File
@@ -0,0 +1,79 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include <libssh/libssh.h>
#include <libssh/sftp.h>
/* codes a passer a la fonction setError */
enum {
WSSH_MEM_ERROR = -2,
WSSH_ERROR = -1,
WSSH_OK = 0,
WSSH_SESSION = 1,
WSSH_SESSION_CONNECT = 2,
WSSH_AUTH = 3,
WSSH_CHANNEL = 4,
WSSH_CHANNEL_OPEN = 5,
WSSH_WRITE = 6,
WSSH_READ = 7,
WSSH_EXEC = 8,
WSSH_MODE = 9,
WSSH_SFTP = 10,
WSSH_SFTP_INIT = 11
};
enum {
WSSH_EXEC_MODE = 1,
WSSH_TERMINAL_MODE = 0
};
typedef struct {
ssh_session session;
ssh_channel channel; /* commandes console */
sftp_session sftp;
/* */
int err; /* erreur specifique au module */
int packet; /* taille des paquets lus un par un */
int execMode; /* TRUE si channelExec, FALSE si pseudo terminal */
} modContextSsh;
WAPIDECL void initSsh(env * e, modContextSsh * ctx);
WAPIDECL void freeSsh(env * e, modContextSsh * ctx);
WAPIDECL long setSession(env * e, modContextSsh * ctx, Dynamic * host, Dynamic * user, Dynamic * pwd);
WAPIDECL void freeSession(env * e, modContextSsh * ctx);
WAPIDECL long setChannel(env * e, modContextSsh * ctx, int mode);
WAPIDECL void freeChannel(env * e, modContextSsh * ctx);
WAPIDECL long channelExec(env * e, modContextSsh * ctx, Dynamic * data, Dynamic * resultat, number timeout);
WAPIDECL long channelWrite(env * e, modContextSsh * ctx, Dynamic * data);
WAPIDECL long channelRead(env * e, modContextSsh * ctx, Dynamic * data, number timeout);
/* faire idem channel pour "transfert" (sftp) */
WAPIDECL long setSftp(env * e, modContextSsh * ctx);
WAPIDECL void freeSftp(env * e, modContextSsh * ctx);
+288
View File
@@ -0,0 +1,288 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "ssh.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextSsh ctxSsh;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_WSSH_SESSION = 1,
EXMOD_WSSH_CHANNEL = 2,
EXMOD_WSSH_SFTP = 3,
EXMOD_WSSH_WRITECHANNEL = 4,
EXMOD_WSSH_EXECCHANNEL = 5,
EXMOD_WSSH_READCHANNEL = 6,
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Opening ssh session error",
"Opening ssh channel error",
"Opening sftp session error",
"Write channel error",
"Execute channel command error", // 5
"Read channel error"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initSsh(e, &p_etat->ctxSsh);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
freeSsh(e, &p_etat->ctxSsh);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "openSession", 11))
{
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramUsername = getParam(e, "username", 8);
var * paramPassword = getParam(e, "password", 8);
/* ouvre la connexion ssh au serveur */
if(paramHost == NULL || paramUsername == NULL || paramPassword == NULL)
exc = EX_MODPARAM;
else if(paramHost->type != VAR_DYNAMIC || paramUsername->type != VAR_DYNAMIC || paramPassword->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(setSession(e, &p_etat->ctxSsh, paramHost, paramUsername, paramPassword) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SESSION);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "endSession", 10))
{
/* ferme la connexion ssh au serveur */
freeSession(e, &p_etat->ctxSsh);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "execChannel", 11))
{
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
var * paramResponse = getParam(e, "response", 8);
var * paramTimeout = getParam(e, "timeout", 7);
/* envoi d'une commande "one shot", pas besoin du 'openChannel' ici, lecture du resultat avec 'readChannel' et renvoi du resultat dans response, timeout en sec. dans timeout */
if(paramCommand == NULL || paramResponse == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if(var_conv_num(e, paramTimeout, &timeout))
{
if(paramResponse->type != VAR_DYNAMIC)
var_let(e, paramResponse, &e->int_dynamic, FALSE, FALSE);
if(channelExec(e, &p_etat->ctxSsh, paramCommand, paramResponse, timeout) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_EXECCHANNEL);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "openChannel", 11))
{
/* ouvre un canal de type "terminal" avec le serveur
faire un 'readChannel' la premiere fois apres le 'openChannel', puis enchainer les ecritures (commandes) et lectures (resultat) */
if(setChannel(e, &p_etat->ctxSsh, WSSH_TERMINAL_MODE) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_CHANNEL);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "writeChannel", 12))
{
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
if(paramCommand == NULL)
exc = EX_MODPARAM;
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* envoi d'une commande au pseudo-terminal */
if(channelWrite(e, &p_etat->ctxSsh, paramCommand) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_WRITECHANNEL);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "readChannel", 11))
{
/* get param in the right order */
var * paramResponse = getParam(e, "response", 8);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramResponse == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramResponse->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* lecture du resultat d'une commande (stdout dans paramResponse) en mode terminal, timeout en sec. dans timeout */
number timeout;
if(var_conv_num(e, paramTimeout, &timeout))
{
if(channelRead(e, &p_etat->ctxSsh, paramResponse, timeout) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_READCHANNEL);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeChannel", 12))
{
/* ferme le channel mais laisse la connexion au serveur ouverte (mode terminal seulement, inutile en mode exec) */
freeChannel(e, &p_etat->ctxSsh);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "openSftp", 8))
{
/* ouvre un canal de type "transfert" avec le serveur */
if(setSftp(e, &p_etat->ctxSsh) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SFTP);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeSftp", 9))
{
/* ferme le canal "transfert" mais laisse la connexion au serveur ouverte */
freeSftp(e, &p_etat->ctxSsh);
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+307
View File
@@ -0,0 +1,307 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "ssh.h"
#ifdef WINLIB
#include <WinSock2.h>
#else
#include "poll.h"
#include <fcntl.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/*
unix : -lssh -lcrypto -lssl -lz (dependances openssl zlib, verification avec : ldd /usr/lib/libssh.so)
sudo apt update
sudo apt install -y \
openssl libssl-dev \
zlib1g zlib1g-dev \
libssh-dev
openssl → binaire en ligne de commande
libssl-dev → headers + librairies pour compiler en C
zlib1g → runtime
zlib1g-dev → headers (zlib.h) + .so
libssh-dev → headers et libs de développement
windows : libssh.lib (et libssh compile avec msvc sinon ko)
ajouter => libssl.lib libcrypto.lib zlib.lib ws2_32.lib (car dependances openssl, zlib, socket)
git clone https://github.com/microsoft/vcpkg
cd vcpkg
bootstrap-vcpkg.bat
vcpkg install libssh:x64-windows
vcpkg install zlib:x64-windows
vcpkg install openssl:x64-windows
+ compil/link => cl main.c /I"path\to\vcpkg\installed\x64-windows\include" /link /LIBPATH:"path\to\vcpkg\installed\x64-windows\lib" libssh.lib libssl.lib libcrypto.lib zlib.lib ws2_32.lib
=> repertoire ou se trouve vcpkg (install depuis git) :
C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows
À l'exécution il faut :
libssl-*.dll
libcrypto-*.dll
dans :
même dossier que .exe ou dans le PATH
=== CERTIFICAT auto signé
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes
avec windows, c'est pareil, sauf initsocket WAStartup, type SOCKET et pas int, closesocket() et il faut fournir un fichier ca (https://curl.se/ca/cacert.pem) pour la verification des certificats
https://kb.firedaemon.com/...openssl-binary-distributions : binaires openssl sous windows (3.5.6 LTS ok), ok avec libssh 0.12.x (eventuellement 0.11.x)
*/
/* ****** PRIVATE ************************ */
int ssh_read_timeout(env * e, modContextSsh * ctx, Dynamic * data, number timeout)
{
#ifndef WINLIB
struct pollfd fd;
fd.fd = ssh_get_fd(ctx->session),
fd.events = POLLIN;
/* lecture avec timeout */
int cr = poll(&fd, 1, timeout * 1000 / NUM_FACTEUR);
#else
WSAPOLLFD fd;
fd.fd = (SOCKET)ssh_get_fd(ctx->session);
fd.events = POLLRDNORM;
fd.revents = 0;
/* lecture avec timeout */
int cr = WSAPoll(&fd, 1, timeout * 1000 / NUM_FACTEUR);
#endif
if (cr == 0)
return SSH_AGAIN; /* pas de donnees ou timeout */
if (cr < 0)
return SSH_ERROR;
/* lecture des donnees presentes */
return ssh_channel_read(ctx->channel, data->mPtr + data->mLg, ctx->packet, 0); /* 0 signifie lire stdout, 1 pour stderr */
}
static int setSessionCloexec(ssh_session session)
{
#ifndef WINLIB
int fd = (int)ssh_get_fd(session);
int ret = fcntl(fd, F_GETFD);
if(ret != -1)
ret = fcntl(fd, F_SETFD, ret | FD_CLOEXEC);
return (ret == -1); /* TRUE si erreur */
#else
return 0;
#endif
}
/* ****** PUBLIC ************************ */
WAPIDECL void initSsh(env * e, modContextSsh * ctx)
{
ctx->packet = 16000;
ctx->execMode = WSSH_EXEC_MODE; /* for channel management */
ctx->channel = NULL;
ctx->session = NULL;
}
WAPIDECL void freeSsh(env * e, modContextSsh * ctx)
{
freeSession(e, ctx);
}
WAPIDECL long setSession(env * e, modContextSsh * ctx, Dynamic * host, Dynamic * user, Dynamic * pwd)
{
freeSession(e, ctx);
/* */
if((ctx->session = ssh_new()) == NULL)
return (ctx->err = WSSH_SESSION);
/* */
ssh_options_set(ctx->session, SSH_OPTIONS_HOST, host->mPtr);
ssh_options_set(ctx->session, SSH_OPTIONS_USER, user->mPtr);
/* */
if(ssh_connect(ctx->session) != SSH_OK)
{
ssh_free(ctx->session);
ctx->session = NULL;
return (ctx->err = WSSH_SESSION_CONNECT);
}
setSessionCloexec(ctx->session); /* permet fork + execv securises, une fois connecte */
/* */
if(ssh_userauth_password(ctx->session, NULL, pwd->mPtr) != SSH_AUTH_SUCCESS)
{
//ssh_channel_free(ctx->channel);
freeSession(e, ctx);
return (ctx->err = WSSH_AUTH);
}
return (ctx->err = WSSH_OK);
}
WAPIDECL void freeSession(env * e, modContextSsh * ctx)
{
freeChannel(e, ctx);
freeSftp(e, ctx);
if(ctx->session)
{
ssh_disconnect(ctx->session);
ssh_free(ctx->session);
ctx->session = NULL;
}
}
WAPIDECL long setChannel(env * e, modContextSsh * ctx, int mode)
{
freeChannel(e, ctx);
ctx->execMode = mode;
ssh_set_blocking(ctx->session, TRUE); /* bloquant */
/* */
if((ctx->channel = ssh_channel_new(ctx->session)) == NULL)
return (ctx->err = WSSH_CHANNEL);
/* */
if(ssh_channel_open_session(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
if(ctx->execMode == WSSH_EXEC_MODE)
return (ctx->err = WSSH_OK);
/* */
/* Allocation d'un pseudo-terminal + shell interactif (channel reste ouvert dans ce cas) */
if(ssh_channel_request_pty(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
if(ssh_channel_request_shell(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
return (ctx->err = WSSH_OK);
}
WAPIDECL void freeChannel(env * e, modContextSsh * ctx)
{
if(ctx->channel)
{
if(ctx->execMode == WSSH_TERMINAL_MODE)
{
ssh_channel_write(ctx->channel, "exit\n", 5);
ssh_channel_send_eof(ctx->channel);
}
ssh_channel_close(ctx->channel);
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
}
}
WAPIDECL long channelExec(env * e, modContextSsh * ctx, Dynamic * data, Dynamic * resultat, number timeout)
{
long cr;
cr = setChannel(e, ctx, WSSH_EXEC_MODE);
if(cr != WSSH_OK)
return (ctx->err = cr);
/* send command to channel, one shot (ssh_channel_request_exec ferme le channel a chaque commande) */
if(ssh_channel_request_exec(ctx->channel, data->mPtr) != SSH_OK)
cr = (ctx->err = WSSH_EXEC);
else
cr = channelRead(e, ctx, resultat, timeout); /* lecture du resultat en mode bloquant suite a l'envoi de la requete */
/* */
return cr;
}
WAPIDECL long channelWrite(env * e, modContextSsh * ctx, Dynamic * data)
{
if(ctx->execMode != WSSH_TERMINAL_MODE)
return (ctx->err = WSSH_MODE);
/* send command to channel */
if(ssh_channel_write(ctx->channel, data->mPtr, data->mLg) < 0)
return (ctx->err = WSSH_WRITE);
else
return (ctx->err = WSSH_OK);
/* le channel reste ouvert */
}
WAPIDECL long channelRead(env * e, modContextSsh * ctx, Dynamic * data, number timeout)
{
ssh_set_blocking(ctx->session, FALSE); /* non bloquant */
/* read response from serveur */
dynSetLen(e, data, 0);
/* Lire la sortie, mode non bloquant ici (explicite avec read_nonblocking) */
for(;;)
{
if(dynCtrl(e, data, data->mLg + ctx->packet, TRUE))
{
return (ctx->err = WSSH_MEM_ERROR); /* erreur memoire */
}
int nb = ssh_read_timeout(e, ctx, data, timeout);
/* */
if(nb == SSH_ERROR)
return (ctx->err = WSSH_READ);
if(nb == SSH_AGAIN || nb == 0)
return (ctx->err = WSSH_OK); /* rien a lire pour l'instant ou sortie en timeout ou fin des donnees */
/* */
if(nb > 0)
dynSetLen(e, data, data->mLg + nb);
/* continue reading */
}
}
WAPIDECL long setSftp(env * e, modContextSsh * ctx)
{
if((ctx->sftp = sftp_new(ctx->session)) == NULL)
return (ctx->err = WSSH_SFTP);
/* */
if(sftp_init(ctx->sftp) != SSH_OK)
{
freeSftp(e, ctx);
return (ctx->err = WSSH_SFTP_INIT);
}
return (ctx->err = WSSH_OK);
}
/*
sftp_file file = sftp_open(sftp, "/etc/hostname", O_RDONLY, 0); // NULL : erreur open
nbytes = sftp_read(file, buffer, sizeof(buffer)); // tant que nbytes > 0
sftp_close(file);
*/
WAPIDECL void freeSftp(env * e, modContextSsh * ctx)
{
if(ctx->sftp)
{
sftp_free(ctx->sftp);
ctx->sftp = NULL;
}
}
+275 -307
View File
@@ -25,29 +25,28 @@
#include <time.h>
#include <string.h>
#ifdef WINLIB
#include "windows.h"
#else
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
#ifdef WINLIB
#include "windows.h"
#else
#include <sys/utsname.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
@@ -55,17 +54,23 @@ enum {
EXMOD_SYSTEM_UNKNOWNVARENV = 2,
EXMOD_SYSTEM_SETENV = 3,
EXMOD_SYSTEM_UNSETENV = 4,
EXMOD_SYSTEM_GETHOST = 5,
EXMOD_SYSTEM_UNAME = 6,
EXMOD_SYSTEM_FORK = 7
EXMOD_SYSTEM_UNAME = 5,
EXMOD_CMDLINE_ARG = 6,
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Cannot create tmp file",
"Unknown environment variable",
"set environment variable error",
"delete environment variable error",
"Cannot get host name", // 5
"Cannot read command line arguments"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -76,108 +81,151 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// execute(command, returning, capturing)
// getEnv(nom, valeur)
// setEnv(nom, valeur, overwritting)
// getOS(nom) => int uname(struct utsname *buf);
// getHostname(nom, ip) => int uname(struct utsname *buf);
// TODO prevoir un mecanisme de securite, pour autoriser ou non certains fonctions dangereuses (execute, setenv)
//
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "execute", 7))
{
p_etat->error = 0;
// execute(command, returning, capturing)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
int cr, flagCapturing = (param3 != NULL);
if(paramReturnCode->type != VAR_NUMBER)
var_let(e, paramReturnCode, &e->int_number, FALSE, FALSE);
/* */
int cr, flagCapturing = (paramCapturing != NULL);
if(flagCapturing)
{
if(param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
}
if(flagCapturing && exc == OK)
{
dynSetLen(e, param3, 0);
if(paramCapturing->type != VAR_DYNAMIC)
var_let(e, paramCapturing, &e->int_dynamic, FALSE, FALSE);
/* */
dynSetLen(e, paramCapturing, 0);
#ifdef WINLIB
if (!GetTempPathA(param3->mLgmax, param3->mPtr))
exc = EXMOD_SYSTEM_FICTMP;
else if(!GetTempFileNameA(param3->mPtr, "tmp", 0, e->int_dynamic.mPtr))
exc = EXMOD_SYSTEM_FICTMP;
long lg;
if( ! (lg = GetTempPathA(paramCapturing->mLgmax, paramCapturing->mPtr)))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
{
if(lg > paramCapturing->mLgmax)
{
if(dynCtrl(e, paramCapturing, lg, DYN_FALSE) == DYN_OK)
{
if( ! (lg = GetTempPathA(paramCapturing->mLgmax, paramCapturing->mPtr)))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
}
else
exc = EX_MEM;
}
if(exc == OK)
{
dynSetLen(e, paramCapturing, lg);
if(dynCtrl(e, &e->int_dynamic, MAX_PATH, DYN_FALSE) == DYN_OK)
{
if( ! GetTempFileNameA(paramCapturing->mPtr, "tmp", 0, e->int_dynamic.mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
dynSetLen(e, &e->int_dynamic, strlen(e->int_dynamic.mPtr));
}
else
exc = EX_MEM;
}
}
#else
int fd; // pour avoir un nom de fichier temporaire
dynLet(e, &e->int_dynamic, "/tmp/cap_XXXXXX", 15);
if((fd = mkstemp(e->int_dynamic.mPtr)) == -1)
exc = EXMOD_SYSTEM_FICTMP;
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
close(fd);
#endif
@@ -186,298 +234,150 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
if(flagCapturing)
{
dynSetAs(e, param3, param1);
dynIns(e, param3, 1 + dynDcount(e, param3, '>', DYN_NONE, DYN_NONE), DYN_NONE, &e->int_dynamic, '>', DYN_NONE);
cr = system(param3->mPtr);
dynRead(e, param3, e->int_dynamic.mPtr);
// purge fichier temp
remove(e->int_dynamic.mPtr); // pbm windows ?!
dynSetAs(e, paramCapturing, paramCommand);
dynIns(e, paramCapturing, 1 + dynDcount(e, paramCapturing, '>', DYN_NONE, DYN_NONE), DYN_NONE, &e->int_dynamic, '>', DYN_NONE);
cr = system(paramCapturing->mPtr);
dynRead(e, paramCapturing, e->int_dynamic.mPtr);
remove(e->int_dynamic.mPtr); // purge fichier temp
}
else
{
cr = system(param1->mPtr);
cr = system(paramCommand->mPtr);
}
param2->num = cr * NUM_FACTEUR;
paramReturnCode->num = cr * NUM_FACTEUR;
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getEnv", 6))
{
p_etat->error = 0;
/* utilisation de dynRead qui fait le travail */
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
char * varenv = getenv(param1->mPtr);
if(!varenv)
exc = EXMOD_SYSTEM_UNKNOWNVARENV;
if(paramValue->type != VAR_DYNAMIC)
var_let(e, paramValue, &e->int_dynamic, FALSE, FALSE);
char * varenv = getenv(paramVarName->mPtr);
if(varenv == NULL)
exc = setError(p_etat, EXMOD_SYSTEM_UNKNOWNVARENV);
else
{
int lg;
if(dynCtrl(e, param2, (lg = strlen(varenv)), DYN_FALSE) == DYN_OK)
dynLet(e, param2, varenv, lg);
if(dynCtrl(e, paramValue, (lg = strlen(varenv)), DYN_FALSE) == DYN_OK)
dynLet(e, paramValue, varenv, lg);
else
exc = EX_MEM;
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "createEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
// verifier si existe avec getenv, si oui erreur
char * varenv = getenv(param1->mPtr);
char * varenv = getenv(paramVarName->mPtr);
if(varenv)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
else if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
else if (!SetEnvironmentVariableA(paramVarName->mPtr, paramValue->mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = setenv(param1->mPtr, param2->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
int cr = setenv(paramVarName->mPtr, paramValue->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "updateEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
/* 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(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
if (!SetEnvironmentVariableA(paramVarName->mPtr, paramValue->mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = setenv(param1->mPtr, param2->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
int cr = setenv(paramVarName->mPtr, paramValue->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "deleteEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
if(paramVarName == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, NULL))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
if (!SetEnvironmentVariableA(paramVarName->mPtr, NULL))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = unsetenv(param1->mPtr); // suppression
int cr = unsetenv(paramVarName->mPtr); // suppression
if(cr != 0)
{
exc = EXMOD_SYSTEM_UNSETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_UNSETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getOS", 5))
{
p_etat->error = 0;
// uname() donne les infos
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramOScode = getParam(e, "OScode", 6);
if(paramOScode == NULL)
exc = EX_MODPARAM;
else
{
if(paramOScode->type != VAR_DYNAMIC)
var_let(e, paramOScode, &e->int_dynamic, FALSE, FALSE);
#ifdef WINLIB
dynLet(e, param1, "Windows", DYN_LGNONE);
dynLet(e, paramOScode, "Windows", DYN_LGNONE);
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
{
if(dynCtrl(e, param1, (lg = strlen(name.sysname)), DYN_FALSE) == DYN_OK)
dynLet(e, param1, name.sysname, lg);
if(dynCtrl(e, paramOScode, (lg = strlen(name.sysname)), DYN_FALSE) == DYN_OK)
dynLet(e, paramOScode, name.sysname, lg);
else
exc = EX_MEM;
}
else
{
exc = EXMOD_SYSTEM_UNAME;
setError(p_etat, errno);
}
exc = setError(p_etat, EXMOD_SYSTEM_UNAME);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getHostname", 11))
{
// TODO dans sockMod !!
p_etat->error = 0;
// uname() donne les infos
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
DWORD size = param1->mLgmax;
if (!GetComputerNameA(param1->mPtr, &size))
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
if (gethostname(param2->mPtr, param2->mLgmax) == SOCKET_ERROR)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
struct hostent * host_entry;
host_entry = gethostbyname(param2->mPtr);
if (host_entry == NULL)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
dynLet(e, param2, inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]), DYN_LGNONE);
WSACleanup();
}
}
}
}
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
{
if(dynCtrl(e, param1, (lg = strlen(name.nodename)), DYN_FALSE) == DYN_OK)
{
dynLet(e, param1, name.nodename, lg);
// lecture ip
struct hostent * host = gethostbyname(param1->mPtr);
if(host)
{
dynLet(e, param2, inet_ntoa(*(struct in_addr *)host->h_addr_list[0]), DYN_LGNONE);
}
else
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, h_errno);
}
}
else
exc = EX_MEM;
}
else
{
setError(p_etat, errno);
exc = EXMOD_SYSTEM_UNAME;
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fork", 4))
{
// TODO a supprimer, cf. processMod
p_etat->error = 0;
#ifndef UNIX
// faire differemment sous windows : pas de fork dispo ? CreateProcess()
#else
pid_t fils = fork();
if(fils == -1)
{
exc = EXMOD_SYSTEM_FORK;
setError(p_etat, errno);
}
else
{
if(fils == 0)
e->ppid = 0; // process fils
else
e->ppid = fils; // process pere
}
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "wait", 4))
{
// TODO a supprimer, cf. processMod
#ifndef UNIX
// faire differemment sous windows : pas de wait dispo ? WaitForSingleObject()
#else
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
param1->num = waitpid(-1, NULL, WNOHANG) * NUM_FACTEUR; // renvoi le pid d'un fils qui s'est fini, 0 si pas de fils termine
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "sendSignal", 10))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPid = getParam(e, "pid", 3);
var * paramSignalNumber = getParam(e, "signalNumber", 12);
if(paramPid == NULL || paramSignalNumber == NULL)
exc = EX_MODPARAM;
else
{
number pid, numSignal;
if( var_conv_num(e,param1, &pid) && var_conv_num(e, param2, &numSignal) )
if( var_conv_num(e,paramPid, &pid) && var_conv_num(e, paramSignalNumber, &numSignal) )
{
pid /= NUM_FACTEUR;
numSignal /= NUM_FACTEUR;
@@ -523,30 +423,98 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "sleep", 5))
{
if(param1 == NULL)
/* get param in the right order */
var * paramDuration = getParam(e, "duration", 8);
if(paramDuration == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
else if(paramDuration->type != VAR_DYNAMIC && paramDuration->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
// duree attente envoyee en secondes
Sleep(param1->num * 1000 / NUM_FACTEUR); // en millisec.
#else
// duree attente envoyee en secondes, avec les decimales
usleep(param1->num * (1000000 / NUM_FACTEUR)); // en microsec.
#endif
number duration;
if(var_conv_num(e, paramDuration, &duration))
{
#ifdef WINLIB
// duree attente envoyee en secondes
Sleep(duration * 1000 / NUM_FACTEUR); // en millisec.
#else
// duree attente envoyee en secondes, avec les decimales
usleep(duration * (1000000 / NUM_FACTEUR)); // en microsec.
#endif
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "newProcess", 10))
{
/* get param in the right order */
var * paramArgs = getParam(e, "args", 4);
var * paramPid = getParam(e, "newPid", 6);
if(paramArgs == NULL || paramPid == NULL)
exc = EX_MODPARAM;
else if(paramArgs->type != VAR_DYNAMIC) /* progs w + arguments en FM */
exc = EX_MODPARAM;
else
{
if(paramPid->type != VAR_NUMBER)
var_let(e, paramPid, &e->int_number, FALSE, FALSE);
paramPid->num = 0; /* erreur par defaut */
/* lire GUV_ENV et GUV_WARGV{1} pour reconstituer la ligne de commande windows/unix */
var * va = &e->int_dynamic;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_WARGV), &va); // garder {1,1} = executeur W
var * ve = &e->tmp_dynamic;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_ENV), &ve); // wbin wsrc wlib {1,1-3}
if(va && ve)
{
dynStore(e, va, 2, DYN_NONE, ve, cVM, DYN_NONE);
dynField(e, va, ve, 1, DYN_NONE, cVM, DYN_NONE, 4); /* ve = execw wbin wsrc wlib en VM */
dynReplace(e, ve, cVM, cFM);
dynConcatSz(e, ve, sFM, 1);
dynConcat(e, ve, paramArgs); /* ve = execw wbin wsrc wlib progw argw1 etc. en FM */
dynInsSz(e, ve, 2, 1, "-WBIN", 5, cFM, ':');
dynInsSz(e, ve, 3, 1, "-WSRC", 5, cFM, ':');
dynInsSz(e, ve, 4, 1, "-WLIB", 5, cFM, ':');
/* ve (tmp_dynamic) contient la ligne de commande complete */
#ifdef WINLIB
dynReplace(e, ve, cFM, ' '); /* recree une ligne de commande */
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si);
if(CreateProcess(NULL, ve->mPtr, NULL, NULL, FALSE, e->demon ? CREATE_NO_WINDOW : CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) // ou DETACHED_PROCESS comme avec BACK !?
{
paramPid->num = pi.dwProcessId * NUM_FACTEUR; /* ok, code retour = pid du process cree */
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
#else
long pid = fork();
if(pid > 0)
{
/* dans le pere, retourner le pid du process cree */
paramPid->num = pid * NUM_FACTEUR;
}
else if(pid == 0)
{
/* dans le fils : execvp et sortie */
dynField(e, ve, va, 1, DYN_NONE, cFM, DYN_NONE, 1);
char ** argv = dynToTabPtr(e, ve, cFM);
execvp(va->mPtr, argv); /* attention : si programme interactif en front lance (cas exec 'calc') avec acces entree standard => generera une exception car ce n'est pas possible sous Unix (ok windows) */
/* ici, erreur de execvp */
_exit(127); /* mieux que exit(0) !? */
}
#endif
}
else
exc = setError(p_etat, EXMOD_CMDLINE_ARG);
}
}
/* ============================================================================================= */
else
{
setError(p_etat, 0);
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+89 -72
View File
@@ -29,21 +29,28 @@
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_xxx = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Template error"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -54,105 +61,115 @@ 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
/* here */
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
if(p_etat != NULL)
{
/* here */
}
// 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(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
else if(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))
{
/* sample */
if(param1 == NULL)
/* get param in the right order */
var * param = getParam(e, "xxxParam", 8);
if(param == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC && param1->type != VAR_NUMBER)
else if(param->type != VAR_DYNAMIC && param->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
number x;
if(var_conv_num(e, param1, &x))
exc = EXMOD_xxx;
else
if(var_conv_num(e, param, &x))
exc = OK;
else
exc = setError(p_etat, EXMOD_xxx);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+75
View File
@@ -0,0 +1,75 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <time.h>
#include "langage.h"
#include "dynamic.h"
typedef struct {
//*** pour chrono
number start, lap;
//*** pour chrono ; n'est pas un membre d'un objet => global a tous les appels (et n'est pas reentrant - ok en multi process uniquement...)
struct timespec sts;
//*** pour alarme
var alarmList; /* de type hashtable */
//*** pour horodate et alarm, uniquement var tmp
var * dhm, * offset;
struct tm * stm, * stmLocal;
//*** pour alarm, uniquement var tmp
var * delay, * gmt, * nbocc; /* number */
} modContextTime;
#define TIMESTAMP_ISO8601 "A-M-JTh:m:SF"
#define TIMESTAMP_OFFSET_UNKNOWN 999999 // A GARDER ???
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_ALARM_TRIGGERED = -1, /* pas une vraie erreur ici */
EXMOD_GETCLOCK = 1,
EXMOD_FORMAT_KO = 2,
EXMOD_OFFSET_KO = 3,
EXMOD_TIMEDATE_STRING_KO = 4,
EXMOD_TIMEDATE_CONTEXT_KO = 5,
EXMOD_ALARM_CONTEXT_KO = 6
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WAPIDECL void initTime(env * e, modContextTime * ctx);
WAPIDECL void freeTime(env * e, modContextTime * ctx);
WAPIDECL long startChrono(env * e, modContextTime * ctx);
WAPIDECL long getChrono(env * e, modContextTime * ctx, number * duration);
WAPIDECL int setNow(env * e, modContextTime * ctxTime, var * hashTime);
WAPIDECL int setFromTimestamp(env * e, modContextTime * ctxTime, var * hashTime, time_t dhm, long offset);
WAPIDECL int setFromString(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format);
WAPIDECL int getTimeDate(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format, int wantUTC);
WAPIDECL int activateAlarm(env * e, modContextTime * ctxTime, var * name, var * heureDebut, int utc, var * delaiSeconde, int occurences);
WAPIDECL int getNextActivation(env * e, modContextTime * ctxTime, var * name, var * hashTime);
WAPIDECL int getAlarmActive(env * e, modContextTime * ctxTime, var * name, number * active);
WAPIDECL int stopAlarm(env * e, modContextTime * ctxTime, var * name);
WAPIDECL int alarmHasTriggered(env * e, modContextTime * ctxTime, var * name, number reposition, number * triggered);
+251 -625
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -20,9 +20,6 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifdef WINLIB
#include "windows.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
@@ -30,277 +27,38 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
/* ============================================================================================= */
#include "time.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
number start, lap;
//*** pour duree ; n'est pas un membre d'un objet => global a tous les appels (et n'est pas reentrant - ok en multi process uniquement...)
struct timespec sts;
//*** pour horodate
time_t dhm, decalageHoraire;
struct tm stm;
var v;
var * pv;
Dynamic horodate, valNum;
modContextTime ctx;
} modEtat;
#define HORODATE_ISO8601 "A-M-JTh:m:SF"
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_GETCLOCK = 1,
EXMOD_PARAMNUM = 2,
EXMOD_FORMAT_KO = 3,
EXMOD_JETLAG_KO = 4,
EXMOD_DURATION_GETCLOCK = 5
/* codes erreurs dans time.h */
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Read clock time error",
"Format unexpected, bad character",
"Offset error",
"Datetime string format incorrect",
"Internal datetime parameters error", // 5
"Internal alarm parameters error"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
/* fonction locale aux calculs de duree */
static int clock_gettime_monotonic(struct timespec * tv)
{
#ifdef UNIX
return clock_gettime(CLOCK_MONOTONIC, tv);
#else
/* cf stackoverflow */
static LARGE_INTEGER ticksPerSec;
LARGE_INTEGER ticks;
if (!ticksPerSec.QuadPart)
{
QueryPerformanceFrequency(&ticksPerSec);
if(!ticksPerSec.QuadPart)
return -1;
}
QueryPerformanceCounter(&ticks);
tv->tv_sec = (long)(ticks.QuadPart / ticksPerSec.QuadPart);
tv->tv_nsec = (long)(((ticks.QuadPart % ticksPerSec.QuadPart) * 1000000000) / ticksPerSec.QuadPart);
return 0;
#endif
}
/* fonction locale aux alarmes */
static void AddOneDay(env * e, modEtat * p_etat)
{
// horodate au format AAAA-MM-DDThh:mm:ss+99:99
// ajout de 1 jour au format "externe"
// nb jours de chaque mois, d'abord annee normale puis bisextile
static long nbj[24] = {31,28,31,30,31,30,31,31,30,31,30,31,
31,29,31,30,31,30,31,31,30,31,30,31};
long annee, mois, jour, bisextile = 0;
dynField(e, &p_etat->horodate, &p_etat->valNum, 1, 1, 'T', '-', 1);
annee = dynToNum(e, &p_etat->valNum, FALSE, 4);
dynField(e, &p_etat->horodate, &p_etat->valNum, 1, 2, 'T', '-', 1);
mois = dynToNum(e, &p_etat->valNum, FALSE, 2);
dynField(e, &p_etat->horodate, &p_etat->valNum, 1, 3, 'T', '-', 1);
jour = dynToNum(e, &p_etat->valNum, FALSE, 2);
if(annee % 4 == 0 && (annee % 100 != 0 || annee % 400 == 0))
bisextile = 12;
jour += 1;
if(jour > nbj[mois + bisextile - 1])
{
jour = 1;
mois += 1;
if(mois > 12)
{
mois = 1;
annee += 1;
}
}
sprintf(p_etat->horodate.mPtr, "%04ld", annee);
sprintf(p_etat->horodate.mPtr + 5, "%02ld", mois);
sprintf(p_etat->horodate.mPtr + 8, "%02ld", jour);
*(p_etat->horodate.mPtr + 4) = '-';
*(p_etat->horodate.mPtr + 7) = '-';
*(p_etat->horodate.mPtr + 10) = 'T';
}
/* fonctions locales aux horodates */
#define HORODATE_DECALAGEHORAIREINCONNU 999999
#define LIRE1(d,i,e) {if((e=e&&(*d))){i=(*d++);}if(!e)break;}
#define LIRE2(d,i,e) {if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';}}if(!e)break;}
#define LIRE4(d,i,e) {if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';if((e=e&&(*d))){e=e&&((*d)>='0'&&(*d)<='9');i=i*10+(*d++)-'0';}}}}if(!e)break;}
static int MajTm(modEtat * p_etat, const char * format, const char * date)
{
memset(&p_etat->stm, 0, sizeof(p_etat->stm));
p_etat->stm.tm_mday = 1; // le jour du mois ne demarre pas a 0 (ce que fait le numero de mois : 0 a 11)
p_etat->stm.tm_isdst = -1;
p_etat->decalageHoraire = HORODATE_DECALAGEHORAIREINCONNU;
//
int encore = TRUE;
int i, signe;
char * f = (char *)format, * d = (char *)date, c;
while((c = *f++) && encore)
{
switch(c)
{
case 'A':
LIRE4(d,i,encore);
p_etat->stm.tm_year = i - 1900;
break;
case 'a':
LIRE2(d,i,encore);
p_etat->stm.tm_year = i + 100; // pas d'annee avant 2000... mettre une annee pivot ? type si < 50, 20xx sinon 19xx ?
break;
case 'M':
LIRE2(d,i,encore);
p_etat->stm.tm_mon = i - 1;
break;
case 'J':
LIRE2(d,i,encore);
p_etat->stm.tm_mday = i;
break;
case 'h':
LIRE2(d,i,encore);
p_etat->stm.tm_hour = i;
break;
case 'm':
LIRE2(d,i,encore);
p_etat->stm.tm_min = i;
break;
case 's':
LIRE2(d,i,encore);
p_etat->stm.tm_sec = i;
break;
case 'S':
LIRE2(d,i,encore);
p_etat->stm.tm_sec = i;
LIRE1(d,i,encore);
if(i != ',') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
LIRE1(d,i,encore);
if(i < '0' || i > '9') {d--;break;}
// 7 decimales maxi...
break;
case 'F':
LIRE1(d,i,encore);
if(i == 'Z') {p_etat->decalageHoraire=0;break;}
else if(i != '+' && i != '-') {encore=FALSE;break;}
if(i == '-') signe = -1 ; else signe = 1;
LIRE2(d,i,encore);
p_etat->decalageHoraire = signe * i * 3600;
LIRE1(d,i,encore);
if(i != ':') {d--;break;}
LIRE2(d,i,encore);
p_etat->decalageHoraire += signe * i * 60;
break;
default:
LIRE1(d,i,encore);
if(c != i) {encore=FALSE;break;}
break;
}
}
return encore; // true = ok, false = erreur
}
static time_t MkTimeTU(modEtat * p_etat)
{
// utilisation de l'agorithme http://howardhinnant.github.io/date_algorithms.html
// car pas de fonction directe dans time.h : mktime suppose que struct tm est locale
int y, m, d;
y = p_etat->stm.tm_year + 1900;
m = p_etat->stm.tm_mon + 1;
d = p_etat->stm.tm_mday;
//
if(m <= 2) y--;
if(y < 0) y -= 399;
int era = y / 400;
unsigned int yoe = (y - era * 400); // [0, 399]
unsigned int doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1; // [0, 365]
unsigned int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
time_t t = (time_t)(era * 146097 + doe - 719468);
t = t * 86400 + p_etat->stm.tm_hour * 3600 + p_etat->stm.tm_min * 60 + p_etat->stm.tm_sec;
return t;
}
static void FormatTm(env * e, modEtat * p_etat, const char * format, time_t dhm, time_t decalageHoraire)
{
dynSetLen(e, &p_etat->horodate, 0);
char * p = (char *)format, c[2] = {0};
dhm += decalageHoraire;
p_etat->stm.tm_isdst = -1;
p_etat->stm = *gmtime(&dhm);
//
while((c[0] = *p++))
{
switch(c[0])
{
case 'A':
case 'Y':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_year + 1900, FALSE, 4), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'a':
case 'y':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_year % 100, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'M':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_mon + 1, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'J':
case 'D':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_mday, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'h':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_hour, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'm':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_min, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 's':
case 'S':
dynLet(e, &p_etat->valNum, Int64ToSz(e, p_etat->stm.tm_sec, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
break;
case 'F':
if(decalageHoraire == 0)
dynConcatSz(e, &p_etat->horodate, "Z", 1);
else
{
dynConcatSz(e, &p_etat->horodate, decalageHoraire > 0 ? "+" : "-", 1);
//
dynLet(e, &p_etat->valNum, Int64ToSz(e, (abs(decalageHoraire) / 3600) % 100, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
//
dynConcatSz(e, &p_etat->horodate, ":", 1);
//
dynLet(e, &p_etat->valNum, Int64ToSz(e, (abs(decalageHoraire) % 3600) / 60, FALSE, 2), DYN_LGNONE);
dynConcat(e, &p_etat->horodate, &p_etat->valNum);
}
break;
default:
dynConcatSz(e, &p_etat->horodate, c, 1);
break;
}
}
}
/* fonctions locales au module FIN */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
@@ -309,437 +67,305 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODETAT;
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
p_etat->start = 0;
p_etat->lap = 0;
dynInit(e, &p_etat->horodate, DYN_LGMIN);
dynInit(e, &p_etat->valNum, DYN_LGMIN);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initTime(e, &p_etat->ctx);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeTime(e, &p_etat->ctx);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
//*** code specifique ici
dynFree(e, &p_etat->horodate);
dynFree(e, &p_etat->valNum);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "startChrono", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; // variables en parametre du mauvais type
//
if (clock_gettime_monotonic(&p_etat->sts) == -1)
exc = setError(p_etat, EXMOD_GETCLOCK);
else
{
p_etat->start = p_etat->sts.tv_sec * NUM_FACTEUR + (p_etat->sts.tv_nsec / 10000);
param1->num = p_etat->start;
}
exc = setError(p_etat, startChrono(e, &p_etat->ctx));
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "lapChrono", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramDuration = getParam(e, "duration", 8);
if(paramDuration == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; // variables en parametre du mauvais type
//
if (clock_gettime_monotonic(&p_etat->sts) == -1)
exc = setError(p_etat, EXMOD_GETCLOCK);
else
else
{
p_etat->lap = p_etat->sts.tv_sec * NUM_FACTEUR + (p_etat->sts.tv_nsec / 10000);
param1->num = p_etat->lap - p_etat->start;
p_etat->start = p_etat->lap; // permet de refaire un appel de lapChrono
if(paramDuration->type != VAR_NUMBER)
var_let(e, paramDuration, &e->int_number, FALSE, FALSE);
/* */
exc = setError(p_etat, getChrono(e, &p_etat->ctx, &paramDuration->num));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setUTC", 6))
else if(modFnIs(e, "setNow", 6))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
/* get param in the right order */
var * paramHashTime = getParam(e, "timeParameterSet", 16);
if(paramHashTime != NULL)
{
// param2 = format ; param3 = date
if( ! MajTm(p_etat, param2->mPtr, param3->mPtr))
exc = EXMOD_FORMAT_KO;
if(paramHashTime->type == VAR_HASHTABLE)
exc = setError(p_etat, setNow(e, &p_etat->ctx, paramHashTime));
else
{
p_etat->dhm = MkTimeTU(p_etat);
p_etat->decalageHoraire = 0;
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
// param2 = format ; param3 = date
if(!MajTm(p_etat, param2->mPtr, param3->mPtr))
exc = EXMOD_FORMAT_KO;
else
{
p_etat->dhm = MkTimeTU(p_etat);
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
p_etat->dhm -= p_etat->decalageHoraire;
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setNowLocal", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
p_etat->dhm = time(NULL);
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setNowUTC", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
p_etat->dhm = time(NULL);
p_etat->decalageHoraire = 0;
// maj param1avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
/* get param in the right order */
var * paramHashTime = getParam(e, "timeParameterSet", 16);
var * paramTimestamp = getParam(e, "timestamp", 9);
var * paramOffset = getParam(e, "offset", 6);
var * paramString = getParam(e, "string", 6);
var * paramStringFormat = getParam(e, "stringFormat", 12);
/*
seules certaines combinaisons sont prises en charge :
1/ timestamp (UTC), timestamp (local) + offset
2/ string (format ISO8601 fixe A-M-JTh:m:SF), string + stringFormat
timeParameterSet obligatoire dans tous les cas
*/
if(paramHashTime != NULL && paramTimestamp != NULL)
{
// param2 = format ; param3 = date
if( ! MajTm(p_etat, param2->mPtr, param3->mPtr))
exc = EXMOD_FORMAT_KO;
number ntime, noff = NUM_ZERO;
if( ! var_conv_num(e, paramTimestamp, &ntime) || paramString != NULL || paramStringFormat != NULL)
exc = EX_MODPARAM;
else
{
p_etat->dhm = MkTimeTU(p_etat);
if(p_etat->decalageHoraire == HORODATE_DECALAGEHORAIREINCONNU)
exc = EXMOD_JETLAG_KO;
else
{
p_etat->dhm -= p_etat->decalageHoraire;
// maj param1 avec les 2 champs dhm et decalage (number)
p_etat->v.type = VAR_NUMBER;
p_etat->v.num = p_etat->dhm * NUM_FACTEUR;
p_etat->pv = &p_etat->v;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->v.num = p_etat->decalageHoraire * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "jetlag"), &p_etat->pv);
}
if(paramOffset != NULL)
if( ! var_conv_num(e, paramOffset, &noff))
exc = EX_MODPARAM;
if(exc == OK)
exc = setError(p_etat, setFromTimestamp(e, &p_etat->ctx, paramHashTime, (time_t)(ntime / NUM_FACTEUR), (long)(noff / NUM_FACTEUR)));
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getUTC", 6))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
else if(paramHashTime != NULL && paramString != NULL)
{
p_etat->decalageHoraire = 0;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->dhm = (p_etat->pv)->num / NUM_FACTEUR;
//
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
// resultat
dynLet(e, param3, p_etat->horodate.mPtr, DYN_LGNONE);
if(paramString->type != VAR_DYNAMIC || paramTimestamp != NULL || paramOffset != NULL)
exc = EX_MODPARAM;
else
{
if(paramStringFormat != NULL)
if(paramStringFormat->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
if(exc == OK)
exc = setError(p_etat, setFromString(e, &p_etat->ctx, paramHashTime, paramString, paramStringFormat ? paramStringFormat->mPtr : TIMESTAMP_ISO8601));
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
hashtable_do(e, HASH_READ, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->dhm = (p_etat->pv)->num / NUM_FACTEUR;
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
//
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
// resultat
dynLet(e, param3, p_etat->horodate.mPtr, DYN_LGNONE);
}
exc = EX_MODPARAM;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
/* get param in the right order */
var * paramHashTime = getParam(e, "timeParameterSet", 16);
var * paramFormat = getParam(e, "timedateFormat", 14);
var * paramUTC = getParam(e, "timedateUTC", 11);
var * paramResult = getParam(e, "timedateString", 14);
if(paramHashTime != NULL && paramFormat != NULL && paramUTC != NULL && paramResult != NULL)
{
hashtable_do(e, HASH_READ, param1, copy_nom(e, "jetlag"), &p_etat->pv);
p_etat->decalageHoraire = (p_etat->pv)->num / NUM_FACTEUR;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "timestamp"), &p_etat->pv);
p_etat->dhm = (p_etat->pv)->num / NUM_FACTEUR;
//
if(p_etat->decalageHoraire == HORODATE_DECALAGEHORAIREINCONNU)
p_etat->decalageHoraire = 0; // securite : se remettre en UTC
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
// resultat
dynLet(e, param3, p_etat->horodate.mPtr, DYN_LGNONE);
number utc;
if(var_conv_num(e, paramUTC, &utc) && paramHashTime->type == VAR_HASHTABLE && paramFormat->type == VAR_DYNAMIC)
{
if(paramResult->type != VAR_DYNAMIC)
var_let(e, paramResult, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramResult, 0);
/* */
exc = setError(p_etat, getTimeDate(e, &p_etat->ctx, paramHashTime, paramResult, paramFormat->mLg == 0 ? TIMESTAMP_ISO8601 : paramFormat->mPtr, (int)(utc != 0)));
}
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "alarmUTCHM", 10))
else if(modFnIs(e, "setAlarm", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramBegin = getParam(e, "beginning", 4);
var * paramDelay = getParam(e, "delay", 4);
var * paramGmt = getParam(e, "gmt", 3);
var * paramOcc = getParam(e, "occurence", 9);
if(paramName == NULL || paramBegin == NULL || paramDelay == NULL || paramGmt == NULL || paramOcc == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC || paramBegin->type != VAR_DYNAMIC || paramDelay->type != VAR_DYNAMIC ||
(paramGmt->type != VAR_DYNAMIC && paramGmt->type != VAR_NUMBER) || (paramOcc->type != VAR_DYNAMIC && paramOcc->type != VAR_NUMBER))
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
// TODO a tester
ent64s hhmm = param1->num / NUM_FACTEUR;
// param2 = alarme_tfin (sortie) ; param3 = m_Tmp ~ delai (sortie)
long now,alarme_tfin;
now = time(NULL);
p_etat->decalageHoraire = 0;
p_etat->dhm = now;
FormatTm(e, p_etat, HORODATE_ISO8601, p_etat->dhm, p_etat->decalageHoraire);
sprintf(p_etat->horodate.mPtr + 11, "%02lld", hhmm / 100);
p_etat->horodate.mPtr[13] = ':';
sprintf(p_etat->horodate.mPtr + 14, "%02lld", hhmm % 100);
p_etat->horodate.mPtr[16] = ':';
p_etat->horodate.mPtr[17] = '0';
p_etat->horodate.mPtr[18] = '0';
//
if( ! MajTm(p_etat, HORODATE_ISO8601, p_etat->horodate.mPtr))
exc = EXMOD_FORMAT_KO;
else
number ngmt, nocc;
if(var_conv_num(e, paramGmt, &ngmt) && var_conv_num(e, paramOcc, &nocc))
{
alarme_tfin = p_etat->dhm;
if(alarme_tfin < now)
alarme_tfin += 86400;
dynLet(e, param2, Int64ToSz(e, alarme_tfin, FALSE, 19), DYN_LGNONE);
dynLet(e, param3, "86400", 5); // delai
exc = setError(p_etat, activateAlarm(e, &p_etat->ctx, paramName, paramBegin, (int)(ngmt != 0), paramDelay, (int)(nocc / NUM_FACTEUR)));
}
else
exc = setError(p_etat, EX_MODPARAM);
}
}
else if(modFnIs(e, "stopAlarm", 9))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
if(paramName == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, stopAlarm(e, &p_etat->ctx, paramName));
}
}
else if(modFnIs(e, "getNextActivation", 17))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramNext = getParam(e, "nextTime", 8);
if(paramName == NULL || paramNext == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC || paramNext->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, getNextActivation(e, &p_etat->ctx, paramName, paramNext));
}
}
else if(modFnIs(e, "alarmActive", 11))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramActive = getParam(e, "isActive", 8);
if(paramName == NULL || paramActive == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramActive->type != VAR_NUMBER)
var_let(e, paramActive, &e->int_number, FALSE, FALSE);
paramActive->num = 0;
exc = setError(p_etat, getAlarmActive(e, &p_etat->ctx, paramName, &paramActive->num));
}
}
else if(modFnIs(e, "triggeredAlarm", 14))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramTriggered = getParam(e, "triggered", 9);
var * paramReposition = getParam(e, "reposition", 10); /* optionnel, par defaut @true = 1 : se recaler */
if(paramName == NULL || paramTriggered == NULL)
exc = EX_MODPARAM;
else if(paramName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
int repos = 1;
if(paramReposition != NULL)
{
if(paramReposition->type != VAR_DYNAMIC && paramReposition->type != VAR_NUMBER)
exc = EX_MODPARAM;
else if( ! var_conv_num(e, paramReposition, &e->int_number.num))
exc = EX_MODPARAM;
else
repos = (int)(e->int_number.num != 0);
}
/* */
if(exc == OK)
{
if(paramTriggered->type != VAR_NUMBER)
var_let(e, paramTriggered, &e->int_number, FALSE, FALSE);
/* */
paramTriggered->num = 0;
exc = setError(p_etat, alarmHasTriggered(e, &p_etat->ctx, paramName, repos, &paramTriggered->num));
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "alarmLocalHM", 12))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // variables en parametre du mauvais type
else
{
// TODO prendre la version debuggee + a tester
ent64s hhmm = param1->num / NUM_FACTEUR;
// param2 = alarme_tfin (sortie) ; param3 = m_Tmp ~ delai (sortie)
long alarme_tfin, now;
now = time(NULL);
p_etat->dhm = now;
// calcul decalage horaire local
struct tm stm, stmtu;
stm.tm_isdst = -1;
stm = *localtime(&p_etat->dhm);
stmtu = *gmtime(&p_etat->dhm);
p_etat->decalageHoraire = (stm.tm_isdst == 1 ? 3600 : 0); // gestion heure d'ete
p_etat->decalageHoraire += mktime(&stm) - mktime(&stmtu); // modifie stm.tm_isdst !
//
FormatTm(e, p_etat, param2->mPtr, p_etat->dhm, p_etat->decalageHoraire);
sprintf(p_etat->horodate.mPtr + 11, "%02lld", hhmm / 100);
p_etat->horodate.mPtr[13] = ':';
sprintf(p_etat->horodate.mPtr + 14, "%02lld", hhmm % 100);
p_etat->horodate.mPtr[16] = ':';
p_etat->horodate.mPtr[17] = '0';
p_etat->horodate.mPtr[18] = '0';
//
if( ! MajTm(p_etat, HORODATE_ISO8601, p_etat->horodate.mPtr))
exc = EXMOD_FORMAT_KO;
else
{
alarme_tfin = p_etat->dhm;
if(alarme_tfin < now)
{
// ajouter un jour sur le format "externe" ISO8601, idem quand echue pour calcul suivant
AddOneDay(e, p_etat);
// TODO : convertir les 2 lignes a suivre
if( ! MajTm(p_etat, HORODATE_ISO8601, p_etat->horodate.mPtr))
exc = EXMOD_FORMAT_KO;
else
{
p_etat->dhm = MkTimeTU(p_etat);
if(p_etat->decalageHoraire == HORODATE_DECALAGEHORAIREINCONNU)
exc = EXMOD_JETLAG_KO;
else
{
p_etat->dhm -= p_etat->decalageHoraire;
alarme_tfin = p_etat->dhm;
dynLet(e, param2, Int64ToSz(e, alarme_tfin, FALSE, 19), DYN_LGNONE);
dynLet(e, param3, p_etat->horodate.mPtr, 5); // delai
}
}
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+671
View File
@@ -0,0 +1,671 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifdef WINLIB
#include "windows.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
#include "time.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
#define TIME_DHM "dhm"
#define TIME_OFFSET "offset"
#define TIME_TM_TU "stm"
#define TIME_TM_LOCAL "stmLocal"
#define ALARM_NB_OCC "nbocc"
#define ALARM_DELAY "delay"
#define ALARM_DELAYGMT "gmt"
enum {
ALARM_STOP = -1 /* value of "nbocc" field */
};
/* ***** PRIVATE *************** */
static int clockGettimeMonotonic(modContextTime * ctx)
{
#ifdef UNIX
return clock_gettime(CLOCK_MONOTONIC, &ctx->sts);
#else
/* cf stackoverflow */
static LARGE_INTEGER ticksPerSec;
LARGE_INTEGER ticks;
if (!ticksPerSec.QuadPart)
{
QueryPerformanceFrequency(&ticksPerSec);
if(!ticksPerSec.QuadPart)
return -1; /* compatible Unix version */
}
QueryPerformanceCounter(&ticks);
ctx->sts.tv_sec = (long)(ticks.QuadPart / ticksPerSec.QuadPart);
ctx->sts.tv_nsec = (long)(((ticks.QuadPart % ticksPerSec.QuadPart) * 1000000000) / ticksPerSec.QuadPart);
return OK; /* compatible Unix version */
#endif
}
static var * checkAndCreateHashtableItemNumber(env * e, var * hash, const char * name, number defaut)
{
if(strlen(name) > 24)
return NULL;
var * v;
hashtable_do(e, HASH_READ, hash, copy_nom(e, name), &v);
if(!v)
{
v = &e->int_number;
v->num = defaut;
/* */
v = hashtable_writeinfirstfreeentry(e, hash, copy_nom(e, name), v);
}
return v;
}
static var * checkAndCreateHashtableItemDynamic(env * e, var * hash, const char * name, int defaut, int size)
{
if(strlen(name) > 24)
return NULL;
var * v;
hashtable_do(e, HASH_READ, hash, copy_nom(e, name), &v);
if(!v)
{
v = &e->int_dynamic;
var_resize(e, v, size, 0);
if(e->exception != OK)
{
e->exception = OK;
return NULL;
}
/* */
v = hashtable_writeinfirstfreeentry(e, hash, copy_nom(e, name), v);
memset(v->ptr, defaut, size);
}
return v;
}
static int checkHashTime(env * e, modContextTime * ctx, var * hashTime)
{
var * v;
if(!(ctx->dhm = checkAndCreateHashtableItemNumber(e, hashTime, TIME_DHM, (number)0)))
return FALSE;
if(!(ctx->offset = checkAndCreateHashtableItemNumber(e, hashTime, TIME_OFFSET, TIMESTAMP_OFFSET_UNKNOWN)))
return FALSE;
if(!(v = checkAndCreateHashtableItemDynamic(e, hashTime, TIME_TM_TU, 0, sizeof(struct tm))))
return FALSE;
ctx->stm = (struct tm *)(v->ptr);
if(!(v = checkAndCreateHashtableItemDynamic(e, hashTime, TIME_TM_LOCAL, 0, sizeof(struct tm))))
return FALSE;
ctx->stmLocal = (struct tm *)(v->ptr);
/* */
return TRUE;
}
static int checkHashAlarm(env * e, modContextTime * ctx, var * hash)
{
if( ! checkHashTime(e, ctx, hash)) /* next activation */
return FALSE;
if(!(ctx->delay = checkAndCreateHashtableItemNumber(e, hash, ALARM_DELAY, (number)0)))
return FALSE;
if(!(ctx->gmt = checkAndCreateHashtableItemNumber(e, hash, ALARM_DELAYGMT, (number)1)))
return FALSE;
if(!(ctx->nbocc = checkAndCreateHashtableItemNumber(e, hash, ALARM_NB_OCC, ALARM_STOP)))
return FALSE;
/* */
return TRUE;
}
static int checkAlarmName(env * e, var * name)
{
if(!name)
return FALSE;
if(name->type != VAR_DYNAMIC)
return FALSE;
if(name->mLg < 1 || name->mLg > 24)
return FALSE;
/* */
char c = name->mPtr[0];
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
{
for(int i = 1; i < name->mLg; i++)
{
c = name->mPtr[i];
if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
continue;
else
return FALSE;
}
return TRUE;
}
else
return FALSE;
}
static var * getHashAlarm(env * e, modContextTime * ctx, var * name)
{
if( ! checkAlarmName(e, name))
return NULL;
var * hash;
hashtable_do(e, HASH_READ, &ctx->alarmList, name->mPtr, &hash);
if(hash)
if(hash->type != VAR_HASHTABLE)
hash = NULL; /* securite */
return hash;
}
static int isDigit(char ** p, int n, int * val)
{
char c;
*val = 0;
while(n--)
{
c = **p;
(*p)++;
if(c < '0' || c > '9')
return FALSE;
*val = *val * 10 + (c - '0');
}
return TRUE;
}
static void setFromStm(env * e, modContextTime * ctxTime, var * hashTime, int utc)
{
struct tm stm = *ctxTime->stm;
stm.tm_isdst = -1;
ctxTime->dhm->num = mktime(&stm); /* mktime assume que stm est en local */
/* et donc se remettre en TU si demande */
if(utc)
ctxTime->dhm->num += 3600 * (stm.tm_isdst + 1);
setFromTimestamp(e, ctxTime, hashTime, ctxTime->dhm->num, 0);
}
void timeDebug(env * e, modContextTime * ctxTime, var * hashTime)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return;
/* */
printf("-----------------\n");
printf("struct tm (TU) : %04d/%02d/%02d %02d:%02d:%02d\n", ctxTime->stm->tm_year + 1900, ctxTime->stm->tm_mon + 1, ctxTime->stm->tm_mday, ctxTime->stm->tm_hour, ctxTime->stm->tm_min, ctxTime->stm->tm_sec);
printf("struct tmLocal : %04d/%02d/%02d %02d:%02d:%02d\n", ctxTime->stmLocal->tm_year + 1900, ctxTime->stmLocal->tm_mon + 1, ctxTime->stmLocal->tm_mday, ctxTime->stmLocal->tm_hour, ctxTime->stmLocal->tm_min, ctxTime->stmLocal->tm_sec);
printf("time_t dhm : %lld\n", ctxTime->dhm->num);
printf("decalage offset: %lld\n", ctxTime->offset->num);
time_t t = (time_t)(ctxTime->dhm->num - ctxTime->offset->num); /* ctime() renvoi le format "local"... */
printf("ctime dhm : %s", ctime(&t));
t = (time_t)(ctxTime->dhm->num);
printf("ctime dhm + off: %s", ctime(&t));
printf("-----------------\n");
}
void alarmDebug(env * e, modContextTime * ctxTime)
{
//
var * v = &e->int_hash;
var * vn = &e->int_number;
hashtable_select(e, &ctxTime->alarmList);
while(hashtable_next(e, &ctxTime->alarmList, e->tmp_dynamic.mPtr, &v))
{
printf("==================\n");
printf("alarm name : %s\n", e->tmp_dynamic.mPtr);
hashtable_do(e, HASH_READ, v, copy_nom(e, ALARM_DELAY), &vn);
if(vn) printf("alarm delay : %lld\n", vn->num);
hashtable_do(e, HASH_READ, v, copy_nom(e, ALARM_DELAYGMT), &vn);
if(vn) printf("alarm gmt : %lld\n", vn->num);
hashtable_do(e, HASH_READ, v, copy_nom(e, ALARM_NB_OCC), &vn);
if(vn) printf("alarm occur. : %lld\n", vn->num);
/* next activation */
timeDebug(e, ctxTime, v);
}
}
/* *********************************************************************************************************** */
/* ***** PUBLIC *************** */
WAPIDECL void initTime(env * e, modContextTime * ctx)
{
ctx->start = NUM_ZERO;
ctx->lap = NUM_ZERO;
var_init(e, &ctx->alarmList, VAR_HASHTABLE, 3, 8, NULL);
}
WAPIDECL void freeTime(env * e, modContextTime * ctx)
{
var_free(e, &ctx->alarmList, TRUE);
}
/* for Chrono methods */
WAPIDECL long startChrono(env * e, modContextTime * ctx)
{
if (clockGettimeMonotonic(ctx) != OK)
return EXMOD_GETCLOCK;
else
{
ctx->start = ctx->sts.tv_sec * NUM_FACTEUR + (ctx->sts.tv_nsec / 10000);
return OK;
}
}
WAPIDECL long getChrono(env * e, modContextTime * ctx, number * duration)
{
if (clockGettimeMonotonic(ctx) != OK)
return EXMOD_GETCLOCK;
else
{
ctx->lap = ctx->sts.tv_sec * NUM_FACTEUR + (ctx->sts.tv_nsec / 10000);
*duration = ctx->lap - ctx->start;
ctx->start = ctx->lap; // permet de refaire un appel de lapChrono
return OK;
}
}
/* for time and date =>
Permet de stocker une horodate en masquant les complications liees aux bibliotheques standards C :
. mettre une horodate dans l'objet en utilisant une des methodes "set"
. recuperer l'horodate selon le format voulu en utilisant une des methodes "get"
hash.dhm, hash.offset : number (binaire)
hash.stm, hash.stmLocal : dynamic (mode "binaire")
*/
WAPIDECL int setNow(env * e, modContextTime * ctxTime, var * hashTime)
{
return setFromTimestamp(e, ctxTime, hashTime, time(NULL), 0);
}
WAPIDECL int setFromTimestamp(env * e, modContextTime * ctxTime, var * hashTime, time_t dhm, long offset)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return EXMOD_TIMEDATE_CONTEXT_KO;
/* */
/* offset donne le decalage horaire de dhm, dhm exprime en local (0 si UTC, cas de time(NULL) ) */
ctxTime->dhm->num = dhm - offset; // se remettre en TU
// calcul decalage horaire local
ctxTime->stm->tm_isdst = -1;
ctxTime->stmLocal->tm_isdst = -1;
time_t t = (time_t)(ctxTime->dhm->num);
*ctxTime->stmLocal = *localtime(&t);
*ctxTime->stm = *gmtime(&t);
/* */
struct tm stml = *ctxTime->stmLocal;
struct tm stmg = *ctxTime->stm;
ctxTime->offset->num = ctxTime->stmLocal->tm_isdst == 1 ? 3600 : 0; /* heure ete/hiver */
ctxTime->offset->num += mktime(&stml) - mktime(&stmg); /* modifie les struct tm ! donc utiliser des vars tempo */
//ctxTime->dhm->num -= ctxTime->offset->num; // a enlever car dhm en local (si en UTC, offset doit etre passe a 0, donc c'est pareil que toujours en local)
return OK;
}
/*
Formatage d'une Horodate :
A Y : annee sur 4 chiffres
a y : annee sur 2 chiffres ( 0 => 2000 )
M : mois sur 2 chiffres
L : mois sur 3 lettres (RFC822/5322) Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
J D : jour sur 2 chiffres
l : jour de la semaine sur 3 lettres (RFC822/5322) Mon Tue Wed Thu Fri Sat Sun
h : heure sur 2 chiffres
m : minutes sur 2 chiffres
S : secondes sur 2 chiffres avec les fractions de secondes (de 0 a 7 decimales), exemple "12,456" ou "01.1234567" (les fractions de secondes sont ignorees et ne sont pas memorisees)
s : secondes sur 2 chiffres
F : fuseau horaire, soit "Z" pour UTC, soit "+/-mm:ss" heures et minutes en plus ou moins, exemples "+01:00" "-02:30" etc.
f : zone (RFC822/5322) UT GMT EST EDT CST CDT MST MDT PST PDT
0 0 -5 -4 -6 -5 -7 -6 -8 -7
g : zone (RFC822/1522 militaire) (1,1,a-ik-zA-IK-Z) ; A à M : -1 à -12 ; N à Y : +1 à +12 ; Z = UTC
n : zone numerique (1,1,+-) (4,4,0-9) : +0000 pour UTC, +0200, -0100, etc.
*/
WAPIDECL int setFromString(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return EXMOD_TIMEDATE_CONTEXT_KO;
/* */
memset(ctxTime->stm, 0, sizeof(struct tm));
memset(ctxTime->stmLocal, 0, sizeof(struct tm));
ctxTime->dhm->num = 0;
ctxTime->offset->num = TIMESTAMP_OFFSET_UNKNOWN;
/* */
struct tm stm = {0};
stm.tm_isdst = -1;
/* */
char * d = dhm->mPtr, * f = (char *)format, fc;
int value;
for(;;)
{
if((fc = *f++) == 0) break;
/* */
if(fc == 'A' || fc == 'Y')
{
if( ! isDigit(&d, 4, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_year = value - 1900;
}
else if(fc == 'a' || fc == 'y')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_year = value + 100; /* pas d'annee avant 2000 => mettre une annee pivot du style si < 50, 20xx sinon 19xx ? */
}
else if(fc == 'M')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_mon = value - 1; /* mois de 0 a 11 */
}
else if(fc == 'J' || fc == 'D')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_mday = value; /* jour de 1 a 31 */
}
else if(fc == 'h')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_hour = value; /* heure de 0 a 23 */
}
else if(fc == 'm')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_min = value; /* minutes de 0 a 59 */
}
else if(fc == 's')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_sec = value; /* secondes de 0 a 59 */
}
else if(fc == 'S')
{
if( ! isDigit(&d, 2, &value)) return EXMOD_TIMEDATE_STRING_KO;
stm.tm_sec = value; /* secondes de 0 a 59 */
/* tester 7 decimales (pas d'erreur si non present) */
if(*d == ',' || *d == '.')
{
d++;
for(int ndec = 1; ndec <= 7; ndec++, d++)
if(*d < '0' || *d > '9')
break;
}
}
else if(fc == 'F')
{
if(*d == 'Z')
{
ctxTime->offset->num = 0;
d++;
}
else if(*d == '+' || *d == '-')
{
int signe = (*d++ == '-') ? -1 : 1;
if( ! isDigit(&d, 2, &value))
return EXMOD_TIMEDATE_STRING_KO;
ctxTime->offset->num = signe * value * 3600; // decalage en secondes
if(*d++ != ':')
return EXMOD_TIMEDATE_STRING_KO;
if( ! isDigit(&d, 2, &value))
return EXMOD_TIMEDATE_STRING_KO;
ctxTime->offset->num += signe * value * 60; // decalage en secondes
}
else
return EXMOD_TIMEDATE_STRING_KO; // erreur : le format ne correspond pas a la chaine d'entree
}
else
{
if(*d++ != fc) return EXMOD_TIMEDATE_STRING_KO; // erreur : le format ne correspond pas a la chaine d'entree
}
}
if(*d != 0)
return EXMOD_TIMEDATE_STRING_KO; // fin de "format" mais pas en fin de chaine en entree "dhm"
/* maj struct stm et stmLocal */
ctxTime->dhm->num = mktime(&stm); /* mktime assume que stm est en local */
/* si fuseau horaire absent, local pris en compte par defaut */
if(ctxTime->offset->num == 0)
ctxTime->dhm->num += 3600 * (stm.tm_isdst + 1); /* stm en UTC : corriger */
setFromTimestamp(e, ctxTime, hashTime, ctxTime->dhm->num, 0); /* toujours en UTC ici */
/* */
return OK;
}
WAPIDECL int getTimeDate(env * e, modContextTime * ctxTime, var * hashTime, Dynamic * dhm, const char * format, int wantUTC)
{
if( ! checkHashTime(e, ctxTime, hashTime))
return EXMOD_TIMEDATE_CONTEXT_KO;
/* */
struct tm stm;
stm = (wantUTC ? *ctxTime->stm : *ctxTime->stmLocal);
/* */
char months[48] = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0";
char days[28] = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0";
/* */
char * f = (char *)format, fc, fs[2] = {0};
for(;;)
{
if((fc = *f++) == 0) break;
/* */
if(fc == 'Y' || fc == 'A')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_year + 1900, FALSE, 4), 4);
}
else if(fc == 'y' || fc == 'a')
{
dynConcatSz(e, dhm, Int32ToSz((stm.tm_year + 1900) % 100, FALSE, 2), 2);
}
else if(fc == 'M')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_mon + 1, FALSE, 2), 2);
}
else if(fc == 'L')
{
if(stm.tm_mon >= 0 && stm.tm_mon <= 11)
dynConcatSz(e, dhm, months + stm.tm_mon * 4, 3);
}
else if(fc == 'J' || fc == 'D')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_mday, FALSE, 2), 2);
}
else if(fc == 'l')
{
if(stm.tm_wday >= 0 && stm.tm_wday <= 6)
dynConcatSz(e, dhm, days + stm.tm_wday * 4, 3);
}
else if(fc == 'h')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_hour, FALSE, 2), 2);
}
else if(fc == 'm')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_min, FALSE, 2), 2);
}
else if(fc == 's' || fc == 'S')
{
dynConcatSz(e, dhm, Int32ToSz(stm.tm_sec, FALSE, 2), 2);
}
else if(fc == 'F')
{
if(wantUTC)
dynConcatSz(e, dhm, "Z", 1);
else
{
dynConcatSz(e, dhm, (ctxTime->offset < 0) ? "-" : "+", 1);
dynConcatSz(e, dhm, Int32ToSz(abs(ctxTime->offset->num) / 3600, FALSE, 2), 2);
dynConcatSz(e, dhm, ":", 1);
dynConcatSz(e, dhm, Int32ToSz((abs(ctxTime->offset->num) % 3600) / 60, FALSE, 2), 2);
}
}
else
{
fs[0] = fc;
dynConcatSz(e, dhm, fs, 1);
}
}
return OK;
}
/* for alarms */
WAPIDECL int activateAlarm(env * e, modContextTime * ctxTime, var * name, var * heureDebut, int utc, var * delaiSeconde, int occurences)
{
if( ! checkAlarmName(e, name))
return EXMOD_ALARM_CONTEXT_KO;
if(!heureDebut || !delaiSeconde)
return EXMOD_ALARM_CONTEXT_KO;
if(heureDebut->type != VAR_DYNAMIC || delaiSeconde->type != VAR_DYNAMIC) /* format hh:mm:ss */
return EXMOD_ALARM_CONTEXT_KO;
/*
differents type de gestion :
- a partir de l'heure courante, declencher l'alarme toutes les x secondes, avec un nombre d'occurences limite ou non
- déclenchement à une heure fixe, avec un délai ou non : toutes les heures pleines, toutes les heures et 23 minutes, délai de 1j, 1h, 15 mn, etc. et avec un nombre d'occurences limité ou non
=> donc, parametre heure de debut en TU ou en local, délai entre chaque alarme (TU ou local idem debut) et nombre d'occurence. heure debut <vide> = tout de suite, nb occurence 0 = tout le temps
heureDebut et delaiSecondes en format "externe" hh:mm:ss (converti en secondes en interne dans delay, attention au chgt d'heure !), en tu = 1 oui, 0 en local
alarmList : hashtable, contenant les alarmes, chacune etant une autre hastable
alarmList!name: hashtable
alarmList!name.dhm .offset : number(binaire), prochaine echeance
alarmList!name.stm .stmLocal : dynamic (mode "binaire"), prochaine echeance
alarmList!name.delay .nbocc .gmt: number, delay en secondes, gmt flag 0/1 si delay sur la base du TU (1) ou du Local (0)
*/
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
{
/* creer l'alarme (uniquement lors de l'activation, si besoin) */
hash = &e->int_hash;
e->int_hash.type = VAR_HASHTABLE;
var_resize(e, hash, 3, 8);
if(e->exception != OK)
{
e->exception = OK;
return EXMOD_ALARM_CONTEXT_KO;
}
hashtable_do(e, HASH_WRITE, &ctxTime->alarmList, name->mPtr, &hash);
hash = hashtable_lastitemwritten(&ctxTime->alarmList); /* car HASH_WRITE fait une copie */
}
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* */
number h,m,s, d;
h = dynFieldAsNumber(e, heureDebut, 1, DYN_NONE, ':', DYN_NONE);
m = dynFieldAsNumber(e, heureDebut, 2, DYN_NONE, ':', DYN_NONE);
s = dynFieldAsNumber(e, heureDebut, 3, DYN_NONE, ':', DYN_NONE);
d = dynFieldAsNumber(e, delaiSeconde, 1, DYN_NONE, ':', DYN_NONE) * 3600 + dynFieldAsNumber(e, delaiSeconde, 2, DYN_NONE, ':', DYN_NONE) * 60 + dynFieldAsNumber(e, delaiSeconde, 3, DYN_NONE, ':', DYN_NONE);
/* */
ctxTime->gmt->num = (number)utc;
ctxTime->nbocc->num = (number)occurences;
ctxTime->delay->num = d;
/* */
setNow(e, ctxTime, hash);
if(heureDebut->mLg > 0)
{
/* ajuster le demarrage */
ctxTime->stm->tm_hour = h;
ctxTime->stm->tm_min = m;
ctxTime->stm->tm_sec = s;
setFromStm(e, ctxTime, hash, utc);
}
else
ctxTime->dhm->num += ctxTime->delay->num;
/* */
/* calculate next activation */
while(ctxTime->dhm->num < time(NULL))
ctxTime->dhm->num += ctxTime->delay->num;
setFromTimestamp(e, ctxTime, hash, ctxTime->dhm->num, 0); /* toujours en UTC ici */
/* heure locale pour prochaine activation (idem triggered) ?? */
return OK;
}
WAPIDECL int getNextActivation(env * e, modContextTime * ctxTime, var * name, var * hashTime)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* */
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_DHM), &ctxTime->dhm);
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_OFFSET), &ctxTime->offset);
var * v = &e->int_dynamic;
v->mLg = sizeof(struct tm);
memcpy(e->int_dynamic.mPtr, ctxTime->stm, v->mLg);
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_TM_TU), &v);
memcpy(e->int_dynamic.mPtr, ctxTime->stmLocal, v->mLg);
hashtable_do(e, HASH_WRITE, hashTime, copy_nom(e, TIME_TM_LOCAL), &v);
return OK;
}
WAPIDECL int getAlarmActive(env * e, modContextTime * ctxTime, var * name, number * active)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect : RAS */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* active si pas stoppee */
*active = (ctxTime->nbocc->num != ALARM_STOP) ? NUM_UN : NUM_ZERO;
return OK;
}
WAPIDECL int stopAlarm(env * e, modContextTime * ctxTime, var * name)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect : RAS */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* pour stopper : nbocc mis a -1 */
ctxTime->nbocc->num = ALARM_STOP;
return OK;
}
WAPIDECL int alarmHasTriggered(env * e, modContextTime * ctxTime, var * name, number reposition, number * triggered)
{
var * hash = getHashAlarm(e, ctxTime, name);
if( ! hash)
return EXMOD_ALARM_CONTEXT_KO; /* nom d'alarme inconnu ou incorrect : idem pas echue */
/* */
if( ! checkHashAlarm(e, ctxTime, hash))
return EXMOD_ALARM_CONTEXT_KO;
/* */
*triggered = NUM_ZERO;
/* en temps/duree GMT (TU) suffit ici */
if(ctxTime->nbocc->num > ALARM_STOP && ctxTime->dhm->num <= time(NULL))
{
/* alarm has triggered, calculate next activation */
*triggered = NUM_UN;
/* */
ctxTime->dhm->num += ctxTime->delay->num;
while(reposition && ctxTime->dhm->num < time(NULL))
ctxTime->dhm->num += ctxTime->delay->num;
setFromTimestamp(e, ctxTime, hash, ctxTime->dhm->num, 0); /* toujours en UTC ici */
/* calcul prochaine activation selon heure locale ?? */
/* */
if(ctxTime->nbocc->num > 0)
if( (--ctxTime->nbocc->num) == 0)
ctxTime->nbocc->num = ALARM_STOP;
}
return OK;
}
+124 -88
View File
@@ -111,93 +111,94 @@ WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm
}
}
WAPIDECL int varptrtbl_ctrl(env * e, var * v)
{
/* indique si la var "v" appartient a une var de type pointeur (TRUE) */
if(v == NULL)
return FALSE;
if(v->type == VAR_PARAM)
return FALSE;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad 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
}
// 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)
{
@@ -286,7 +287,7 @@ WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
}
}
// 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)
{
@@ -314,7 +315,10 @@ WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
//
case VAR_PARAM:
if(!suivre_v) // ??
{
var_init(e, let, VAR_PARAM, 0, 0, v->ptr);
let->etat = v->etat;
}
break;
case VAR_BUFFER:
@@ -323,4 +327,36 @@ WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
}
}
WAPIDECL void var_resize(env * e, var * v, ent64 mod_lgm, ent64 sep)
{
if(v == NULL)
{
e->exception = EX_NAVAR;
return;
}
if(v->type == VAR_PARAM)
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* */
if(v->type == VAR_DYNAMIC)
{
if(dynResize(e, v, mod_lgm) != DYN_OK)
e->exception = EX_NAVAR; /* erreur de resize, prevoir une erreur specifique ? */
}
else if(v->type == VAR_HASHTABLE)
{
var_free(e, v, FALSE);
var_init(e, v, VAR_HASHTABLE, mod_lgm, sep, NULL);
if(v->type != VAR_HASHTABLE)
e->exception = EX_NAVAR; /* erreur de resize, prevoir une erreur specifique ? */
}
else
e->exception = EX_NAVAR; /* resize uniquement de dynamic et hashtable, prevoir une erreur specifique ? */
}
/* ********************************************** */
+1
View File
@@ -29,6 +29,7 @@ WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm
WAPIDECL int var_conv_num(env * e, var * v, number * num);
WAPIDECL void var_free(env * e, var * v, int suivre_par);
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
WAPIDECL void var_resize(env * e, var * v, ent64 mod_lgm, ent64 sep);
WAPIDECL int varptrtbl_ctrl(env * e, var * v);
WAPIDECL void varptrtbl_maj(env * e, var * v);