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

Signed-off-by: Deville <nicolas@lanisys.fr>
2026-08-09 20:17:28 +02:00
fred 97065a4e47 fix: lex bug (hard-coded token number) + xml.w 2026-08-09 19:00:43 +02:00
fred 4ed586d2dc feat: named parameters invoking C modules
feat: lex with state management
2026-08-07 17:30:57 +02:00
fred a20c4733ad WIP named parameters invoking C modules + code cleaning 2026-08-02 18:26:50 +02:00
fred ecb07de56e WIP named parameters 2026-08-01 21:02:46 +02:00
fred 9b04cf31ac Merge branch 'dev/alpha-9' of https://git.lanisys.fr/lanisys/W into dev/alpha-9
# Conflicts:
#	pdf_lib.c
2026-08-01 18:49:19 +02:00
fred 6f88a95edd feat: named parametres
feat: cipher AES 128/192/256 bits
feat: pfdMod enables dynamic number of pages + barcode ean128
WIP: named parameters when invoking C module
2026-08-01 18:42:38 +02:00
Lanisys 48719bc369 feat: pdfMod with unknown page number & CAB EAN128 2026-07-26 17:29:44 +02:00
Lanisys 4e7ba72eda fix: readme 2026-07-19 16:14:03 +02:00
Lanisys 726df4dcb9 fix: review readme 2026-07-19 16:12:19 +02:00
fred b6bea78591 feat: release alpha-8 2026-07-14 10:19:52 +02:00
fred 0445f10ebe WIP VAR_PARAM management 2026-06-28 18:01:09 +02:00
fred ad317a2070 feat: ssh_lib, VAR_PARAM management (when hashtable element) 2026-06-28 16:12:04 +02:00
fred e0eaf6f9e8 WIP exception bubbling 2026-06-14 18:14:25 +02:00
fred b70cee802b WIP exception bubbling
WIP ssh lib
2026-06-14 15:45:35 +02:00
fred 84bdea04ea WIP setup for secure socket (openSSL)
fix: cipher lib
2026-06-07 18:26:38 +02:00
fred 747c9819f1 feat: cipher aes128 finalized, aes192 & aes256 to test 2026-05-30 18:58:54 +02:00
fred 44b447e9af feat: hash mod, websocket mod, cipher mod 2026-05-30 17:15:23 +02:00
fred 760020f30e WIP socket, sqlite, createprocess 2026-04-25 19:39:08 +02:00
fred 3f4f548e55 WIP socket module 2026-04-25 15:30:48 +02:00
fred 4c80dff382 WIP linux/windows socket 2026-04-12 18:00:39 +02:00
fred 632df00f8d WIP pdf, socket 2026-04-11 18:17:31 +02:00
fred 667531bee8 WIP 2026-04-08 21:31:51 +02:00
fred 0ec33cbe5a WIP sockMod 2026-04-04 20:29:01 +02:00
fred efbd77e7fb WIP http, sock, template 2026-04-04 18:54:42 +02:00
fred 89dcd0b594 WIP http fcgi 2026-04-04 15:40:08 +02:00
fred 3b68b7d408 WIP http fastcgi 2026-03-31 20:56:49 +02:00
fred e39c18d606 WIP VAR_PARAM management
deat: fcgi_lib
2026-03-29 19:57:17 +02:00
fred fc29d78e57 feat: add rename/remove/append to fileMod + error code 2026-03-28 21:25:58 +01:00
fred cb12b9d54f WIP var_param management 2026-03-28 20:59:27 +01:00
fred bcd62e6913 WIP dynamic convert 2026-03-27 13:52:04 +01:00
fred 89a3c4d5c2 fix: except when returning from LIBR / SUB 2026-03-21 20:55:32 +01:00
fred 103ad22814 feat: add sqrt and exp functions 2026-03-21 19:17:26 +01:00
fred c69d94e6c8 feat: compressed wp programs (assembler and runtime) 2026-03-21 14:50:57 +01:00
fred f994cc8188 fix: DEXV/DEXH/DEXI from number to dynamic
feat: lexMod getToken function
test program calc.w
2026-03-20 20:47:48 +01:00
fred e87d3f9237 feat: convMod (renaming encod_lib), add @variables
fix: lexMod, abs() usage in runtime
feat: dynamic new function (not used yet)
WIP sqrt and exp function in runtime, to do instruction compilation
feat: first real w prog (calculator RPN)
2026-03-20 17:39:44 +01:00
fred 0f55fc23f3 feat: alpha-6, lots of feat and fix 2026-03-15 10:29:17 +01:00
fred fa533a0a2d fix: debug exception display 2026-03-08 18:31:01 +01:00
fred 5ddbd73146 fix: string #hexa escaping, debug local variables, SUBR updated si offset
feat: gened.w test program
2026-03-08 12:11:44 +01:00
fred 80847f4993 feat: lex mod, sortedsearch function
fix: dynIns bug (value in empty attribute), typeof mode
WIP varptrtbl
2026-03-07 18:26:27 +01:00
fred 1fe89c0b6a feat: delete done on hash members
fix: end of line comment formating
2026-02-22 19:13:22 +01:00
fred ddbbb29038 feat: hash.count
fix:DELE woth PVAR, todo with hash
2026-02-21 21:02:07 +01:00
fred eca0605104 feat: foreach numeric, @var oid level, free deleted 2026-02-21 16:06:54 +01:00
fred 72f749172f fix: encod lib Base64 + hash MD5 2026-02-15 13:18:12 +01:00
fred 5c58e7ba97 WIP encod Mod 2026-01-31 11:53:26 +01:00
fred c036ec478c feat: LZW ok with GIF files 2026-01-25 17:23:43 +01:00
fred a23c183f7d WIP socket 2026-01-24 20:38:40 +01:00
fred dc02ac4243 WIP lock 2026-01-24 18:52:46 +01:00
fred 280b10ca99 WIP process & socket 2026-01-18 15:56:38 +01:00
fred db24144e31 feat: debug and quit message on PROG/BACK programs, linux and windows 2026-01-11 18:59:09 +01:00
fred efd1b9a91d feat: ident check and signal/event 2026-01-02 10:56:49 +01:00
fred 33d9ca87c0 fix: debug + copy_nom 2025-12-28 16:38:13 +01:00
fred 4983647ad1 fix: srcdbg 2025-12-27 20:03:35 +01:00
fred dea729767e fix: file source line + debug + sdbg 2025-12-27 18:58:06 +01:00
fred aa61937a20 WIP source line number management 2025-12-25 18:21:33 +01:00
fred 01113671ec WIP src line number management 2025-12-21 18:15:44 +01:00
fred 68d3311b01 fix: object management + this/parent pseudo vars ok + include search for srcdbg 2025-12-21 15:14:29 +01:00
fred 55ad7180e1 fix: pdf time TU 2025-12-14 12:13:43 +01:00
fred a2505eabf7 feat: pdfMod 2025-12-14 12:08:45 +01:00
fred 2ad1bada78 feat: debug background process WIP pdf mod 2025-12-13 17:14:35 +01:00
fred 8460963bc3 WIP shell compilation 2025-12-06 20:21:58 +01:00
fred 4cbc937c45 WIP compilation, debug 2025-12-06 20:20:49 +01:00
fred f60884882c fix: compilation + assemblage 2025-11-30 20:06:45 +01:00
fred 2a07637008 WIP debug background process 2025-11-30 18:48:54 +01:00
fred 6f207a7ed4 WIP namedpipe 2025-11-29 18:32:44 +01:00
fred 2ffcab88b3 WIP 2025-11-29 18:05:15 +01:00
fred a3cc520837 WIP refactoring 2025-11-23 17:43:17 +01:00
fred 22de8f85c5 WIP refactoring #define enum 2025-11-23 17:35:58 +01:00
fred 7019ea7f8b Merge branch 'dev/alpha-4' of https://git.lanisys.fr/lanisys/W into dev/alpha-4 2025-11-23 10:36:57 +01:00
fred 799c7c7548 fix: ticket #1 2025-11-23 10:36:46 +01:00
fred 961994d6c7 Actualiser README.md 2025-11-16 18:58:43 +01:00
fred f8f63d87d4 Actualiser README.md 2025-11-16 18:57:37 +01:00
fred 3384b0df85 feat: arg management in lw lwa lwc 2025-11-16 18:24:08 +01:00
fred fcb62ff71c eat: pdfMod + gestion des arguments en ligne de commande 2025-11-16 16:40:04 +01:00
fred 0871ed56fc WIP divers / shm 2025-10-25 18:42:27 +02:00
fred a6f8d2aefa WIP 2025-09-28 17:56:10 +02:00
95 changed files with 302090 additions and 6142 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://www.lanisys.fr/wiki/doku.php?id=w
# French
## LANGAGE W
@@ -59,19 +34,10 @@ Le but du langage W est d’être simple, efficace, robuste.
Il est fourni avec un compilateur qui génère un code binaire de type
*p-code*, compatible toute plateforme.
Un exécuteur de p-code W sera disponible sur Linux et d’autres OS.
Un interpréteur W permet également d’exécuter un programme W en mode
*script*.
Un module FastCGI permettra de plus d’utiliser le langage W en mode
interprété ou compilé pour les sites Internet.
Enfin, les programmes W pourront être appelés depuis d’autres
Les programmes W pourront être appelés depuis d’autres
programmes, un peu comme un langage de plugins.
Deux utilitaires permettent de formatter le code source et de générer de
la documentation à partir de *tags* dans le code, au format
[DokuWiki](https://www.dokuwiki.org/dokuwiki).
Description du fonctionnement des [programmes](/w/prog) d’exécution et
compilation.
L'utilitaire *lwf* permettent de formatter le code source.
Pour démarrer, premier programme d’exemple :
``` w
@@ -82,4 +48,65 @@ except
end
```
Voici la description complète du [langage W](/w/instr).
# Installation
Installation depuis les dépôts officiels pour base Debian/Ubuntu:
```
sudo apt update
sudo apt install ca-certificates curl
sudo curl -fsSL http://apt.lanisys.fr/public.key -o /etc/apt/keyrings/wlanguage.gpg
sudo tee /etc/apt/sources.list.d/wlanguage.sources <<EOF
Types: deb
URIs: http://apt.lanisys.fr
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: main
Signed-By: /etc/apt/keyrings/wlanguage.gpg
EOF
sudo apt update
sudo apt install wlanguage
sudo exec bash -l
```
Voici la description complète du [langage W](https://w.lanisys.fr/doku.php?id=reference).
# English
## W LANGUAGE
### Overview
The goal of the W language is to be simple, efficient, and robust.
It comes with a compiler that generates *p-code* binary code,
compatible with any platform.
A W p-code executor will be available for Linux and other operating systems.
W programs will be callable from other programs, much like a plugin system.
The *lwf* utility is available for formatting source code.
To get started, here is a first example program:
``` w
; The famous Hello World in W
begin hello
echonl "Hello world !"
except
end
```
# Installation
Installation from the official repositories for Debian/Ubuntu-based systems:
```
sudo apt update
sudo apt install ca-certificates curl
sudo curl -fsSL http://apt.lanisys.fr/public.key -o /etc/apt/keyrings/wlanguage.gpg
sudo tee /etc/apt/sources.list.d/wlanguage.sources <<EOF
Types: deb
URIs: http://apt.lanisys.fr
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: main
Signed-By: /etc/apt/keyrings/wlanguage.gpg
EOF
sudo apt update
sudo apt install wlanguage
sudo exec bash -l
```
Here is the complete description of the [W language](https://w.lanisys.fr/doku.php?id=reference).
+34
View File
@@ -0,0 +1,34 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#undef WAPIDECL
#define WAPIDECL
// for windows compilation and generating/using import library
#ifdef WAPIEXPORT
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#endif
#ifdef WAPIIMPORT
#undef WAPIDECL
#define WAPIDECL __declspec(dllimport)
#endif
+62
View File
@@ -0,0 +1,62 @@
#define ARG_DEBUG "d"
#define ARG_TRACE "t"
#define ARG_DISASM "u"
#define ARG_COMPRESS "c"
void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
{
int nbOpt = 0, cpt = 0, clc = 0;
dynSetLen(e, arg, 0);
dynStoreSz(e, arg, 6, ++clc, argv[0], DYN_LGNONE, cFM, cVM);
for(int a = 1; a < argc; a++)
{
dynStoreSz(e, arg, 6, ++clc, argv[a], DYN_LGNONE, cFM, cVM);
//
if(strcmp(argv[a], "-" ARG_DEBUG) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_DEBUG, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_TRACE) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_TRACE, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_DISASM) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_DISASM, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_COMPRESS) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_COMPRESS, 1, cFM, cVM);
//
else if(strncmp(argv[a], "-WBIN:", 6) == 0 && strlen(argv[a]) > 6)
dynStoreSz(e, arg, 3, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.o .so)
else if(strncmp(argv[a], "-WLIB:", 6) == 0 && strlen(argv[a]) > 6)
dynStoreSz(e, arg, 5, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.wp .wa)
else if(strncmp(argv[a], "-WSRC:", 6) == 0 && strlen(argv[a]) > 6)
dynStoreSz(e, arg, 4, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.w)
else if(strncmp(argv[a], "-", 1) == 0)
; // argument inconnu, ignorer
else
{
// premier argument ne commencant pas par "-" : nom du prog wp
dynDel(e, arg, 6, clc, cFM, cVM, 1);
for( ; a < argc; a++)
dynStoreSz(e, arg, 2, ++cpt, argv[a], DYN_LGNONE, cFM, cVM);
break;
}
}
if(dynExtractPos(e, arg, 3, DYN_NONE, cFM, DYN_NONE) <= 0)
{
dynStoreSz(e, arg, 3, DYN_NONE, getenv("WBIN"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
if(dynExtractPos(e, arg, 3, DYN_NONE, cFM, DYN_NONE) <= 0)
dynStoreSz(e, arg, 3, DYN_NONE, getenv("LD_LIBRARY_PATH"), DYN_LGNONE, cFM, DYN_NONE); // dernier recours...
}
//
if(dynExtractPos(e, arg, 5, DYN_NONE, cFM, DYN_NONE) <= 0)
dynStoreSz(e, arg, 5, DYN_NONE, getenv("WLIB"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
//
if(dynExtractPos(e, arg, 4, DYN_NONE, cFM, DYN_NONE) <= 0)
dynStoreSz(e, arg, 4, DYN_NONE, getenv("WSRC"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
/*
arg<1> = options de lw en MV
arg<2> = prog w et ses parametres en MV
arg<3> = WBIN (.o .so) => invoke, LD_LIBRARY_PATH
arg<4> = WSRC (.w) => lwc
arg<5> = WLIB (.wp .wa) => call, lwa lwc
arg<6> = les argv ligne de commande AVANT le prog wp
*/
}
+269 -284
View File
File diff suppressed because it is too large. Load diff
+76 -32
View File
@@ -29,7 +29,46 @@
#include "buffer.h"
#include "dynamic.h"
void buffer_read(env * e, var * varbuf, var * v)
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/*
Dans le contexte des IPC, memoire partagee, contenant un buffer (donc partagé), le champ "ptr" pointe forcement a la suite de l'entete,
car un malloc ne fonctionne pas en inter process.
Contrairement à la création avec "var_init", destiné a ne pas etre partage, ptr est créé par un malloc
La macro BUFPTR permet de gerer ces 2 cas : si le buffer est en memoire partagee, le champ ptr = NULL et il suffit alors d'aller juste apres l'entete
pour trouver les donnees. Si le buffer est cree avec var_init, il faut utiliser la valeur de ptr directement.
*/
/*
lgmax = taille buffer
max lg message = lgmax - 4 => un message = lg (2 octets) + msg
cas 0 read = write : buffer vide : lg msg max = lgmax - 4 (et maxi 65535)
cas 1 : read <= write (inclus cas 0)
+-------------^*********************^------------------+ lgmax
read write
occ = write - read ; free = lgmax - (write - read) - 4
cas 2 : read > write
+********^---------------------------------------^*****+ lgmax
write read
occ = write + (lgmax - read) ; free = read - write - 4
*/
//#define BUFPTR(x) (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr)
pointeur BUFPTR(var * x)
{
return (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr);
}
WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
{
ent16 lg, lgfin; /* taille max d'un element dans un buffer : 64 Ko */
ent64 p;
@@ -37,9 +76,16 @@ void buffer_read(env * e, var * varbuf, var * v)
return;
if(varbuf->type != VAR_BUFFER)
return;
/* uniquement lecture dans VAR_DYNAMIC : raz var sinon */
/* */
if(v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* uniquement lecture dans VAR_DYNAMIC : raz var sinon */
if(v->type != VAR_DYNAMIC)
{
var_free(e, v, TRUE);
@@ -56,9 +102,9 @@ void buffer_read(env * e, var * varbuf, var * v)
return; /* buffer vide : var dynamic vide aussi */
/* */
p = varbuf->read;
lg = *(octet *)(varbuf->ptr + p++) * 256;
lg = *(octet *)(BUFPTR(varbuf) + p++) * 256;
if(p >= varbuf->lgmax) p = 0;
lg += *(octet *)(varbuf->ptr + p++);
lg += *(octet *)(BUFPTR(varbuf) + p++);
if(p >= varbuf->lgmax) p = 0;
if(lg > 0)
{
@@ -68,8 +114,7 @@ void buffer_read(env * e, var * varbuf, var * v)
if(lg <= (lgfin = varbuf->lgmax - p))
{
/* copier un seul bloc */
memcopie(v->ptr, varbuf->ptr + p, lg);
//memcpy(v->ptr, varbuf->ptr + p, lg);
memcopie(v->ptr, BUFPTR(varbuf) + p, lg);
v->lg = lg;
*(v->ptr + lg) = 0; /* \0 de fin de chaine */
if(p + lg >= varbuf->lgmax)
@@ -80,10 +125,8 @@ void buffer_read(env * e, var * varbuf, var * v)
else
{
/* 2 blocs */
memcopie(v->ptr, varbuf->ptr + p, lgfin);
//memcpy(v->ptr, varbuf->ptr + p, lgfin);
memcopie(v->ptr + lgfin, varbuf->ptr, lg - lgfin);
//memcpy(v->ptr + lgfin, varbuf->ptr, lg - lgfin);
memcopie(v->ptr, BUFPTR(varbuf) + p, lgfin);
memcopie(v->ptr + lgfin, BUFPTR(varbuf), lg - lgfin);
varbuf->read = lg - lgfin;
}
}
@@ -91,17 +134,23 @@ void buffer_read(env * e, var * varbuf, var * v)
varbuf->read = p;
}
void buffer_write(env * e, var * varbuf, var * v)
WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
{
ent64 p, lgfin;
if(varbuf == NULL || v == NULL)
return;
if(v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* uniquement ecriture d'une VAR_DYNAMIC */
if(varbuf->type != VAR_BUFFER || v->type != VAR_DYNAMIC)
return;
/* uniquement ecriture d'une VAR_DYNAMIC */
if(v->lg > (v->lgmax / 16)) // pour pouvoir ecrire au moins 16 items dans le buffer
if(v->lg > (varbuf->lgmax / 2)) // pour pouvoir ecrire au moins 2 items dans le buffer
{
e->exception = EX_BUFOVF; /* trop grand a ecrire */
return;
@@ -117,12 +166,11 @@ void buffer_write(env * e, var * varbuf, var * v)
}
/* */
p = varbuf->write;
*(varbuf->ptr + p) = (v->lg & 65535) >> 8;
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
p++;
*(varbuf->ptr + p) = v->lg & 255;
*(BUFPTR(varbuf) + p) = v->lg & 255;
p++;
memcopie(varbuf->ptr + p, v->ptr, v->lg);
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
varbuf->write = p + v->lg;
}
else
@@ -133,12 +181,11 @@ void buffer_write(env * e, var * varbuf, var * v)
e->exception = EX_BUFOVF; /* pas assez de place */
return;
}
/* */
p = varbuf->write;
*(varbuf->ptr + p) = (v->lg & 65535) >> 8;
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
p++;
if(p >= varbuf->lgmax) p = 0;
*(varbuf->ptr + p) = v->lg & 255;
*(BUFPTR(varbuf) + p) = v->lg & 255;
p++;
if(p >= varbuf->lgmax) p = 0;
if(v->lg == 0)
@@ -149,8 +196,7 @@ void buffer_write(env * e, var * varbuf, var * v)
if(v->lg <= (lgfin = varbuf->lgmax - p))
{
/* copier en une fois */
memcopie(varbuf->ptr + p, v->ptr, v->lg);
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
if(p + v->lg >= varbuf->lgmax)
varbuf->write = 0; /* pas plus cas sinon il y aurait eu copie en 2 fois */
else
@@ -159,16 +205,14 @@ void buffer_write(env * e, var * varbuf, var * v)
else
{
/* en 2 fois */
memcopie(varbuf->ptr + p, v->ptr, lgfin);
//memcpy(varbuf->ptr + p, v->ptr, lgfin);
memcopie(varbuf->ptr, v->ptr + lgfin, v->lg - lgfin);
//memcpy(varbuf->ptr, v->ptr + lgfin, v->lg - lgfin);
memcopie(BUFPTR(varbuf) + p, v->ptr, lgfin);
memcopie(BUFPTR(varbuf), v->ptr + lgfin, v->lg - lgfin);
varbuf->write = v->lg - lgfin;
}
}
}
void buffer_clear(env * e, var * varbuf)
WAPIDECL void buffer_clear(env * e, var * varbuf)
{
if(varbuf == NULL)
return;
@@ -176,10 +220,10 @@ void buffer_clear(env * e, var * varbuf)
return;
varbuf->read = 0;
varbuf->write = 0;
memset(varbuf->ptr, 0, varbuf->lgmax);
memset(BUFPTR(varbuf), 0, varbuf->lgmax);
}
void buffer_printdebug(env * e, var * varbuf, ent32 lg)
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg)
{
if(varbuf == NULL)
return;
@@ -189,5 +233,5 @@ void buffer_printdebug(env * e, var * varbuf, ent32 lg)
if(lg == 0)
lg = varbuf->lgmax;
/* affichage brut en hexa */
hex2((char *)varbuf->ptr, lg, 32);
hex2((char *)BUFPTR(varbuf), lg, 32);
}
+6 -4
View File
@@ -23,11 +23,13 @@
#ifndef BUFFER_H
#define BUFFER_H
void buffer_read(env * e, var * varbuf, var * v);
void buffer_write(env * e, var * varbuf, var * v);
void buffer_clear(env * e, var * varbuf);
#include "apidecl.h"
void buffer_printdebug(env * e, var * varbuf, ent32 lg);
WAPIDECL void buffer_read(env * e, var * varbuf, var * v);
WAPIDECL void buffer_write(env * e, var * varbuf, var * v);
WAPIDECL void buffer_clear(env * e, var * varbuf);
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg);
/* ********************************************** */
#endif
+269
View File
@@ -0,0 +1,269 @@
; w faire une calculatrice RPN : nombre, opérateurs + - * / , fonctions neg frac int mod div , commandes : quitter, clear vide pile (utiliser le module lex), dup (duplique dernier elemn pile), pop enleve dernier element, precision
begin
sub displayStack(stack)
declare size, one, minusOne, elem
let size = dcount(stack)
if size = 0 then
echonl "<empty stack>"
return
endif
let one = 1
let minusOne = neg(one)
foreach elem in size, one, minusOne
echonl format(elem, @right, '0', 2):'> ':format(stack{elem}, @right, ' ', 20)
endfor
except
endsub
;
declare rules, crules, Rule ; lex rules and compiled rules, Rule (pour echapper # 2 fois => #23#32#33)
let crules = ''
let rules = 'integer: int '
let rules{2} = 'fractionnal: frac '
let rules{3} = 'absolute: abs '
let rules{4} = 'negation: neg '
let rules{5} = 'round0: round0 '
let rules{6} = 'round1: round1 '
let rules{7} = 'round2: round2 '
let rules{8} = 'round3: round3 '
let rules{9} = 'round4: round4 '
let rules{10} = 'random: rnd ; random '
let rules{11} = 'varsys: @ (1,*,a-z) '
let rules{12} = 'number: (0,1,#23#32#332D) (1,13,0-9) . (0,5,0-9) ' ; corriger le double 'escape' car - est un car reserve lex (- => #2D => #23#32#33#23#33#32#23#34#34) car sinon compil/assembleur decode mal le -
let rules{13} = 'integernumber: (0,1,#23#32#332D) (1,13,0-9) '
let rules{14} = 'minus: (1,1,#23#32#332D) ; - '
let rules{15} = 'plus: (1,1,#2B) ; + '
let rules{16} = 'multiply: (1,1,#2A) ; * '
let rules{17} = 'divide: (1,1,#2F) ; / '
let rules{18} = 'integerdivide: (1,1,#5C) ; \ '
let rules{19} = 'modulus: (1,1,#25) ; % '
let rules{20} = 'quit: quit '
let rules{21} = 'dup: dup '
let rules{22} = 'pop: pop '
let rules{23} = 'clear: clear '
let rules{24} = 'space: (1,1,#23#32#3320) '
let rules{25} = 'other: (1,1,#23#32#3300-#23#32#33FF)'
let rules = change(rules, @fm, @lf)
part 1
let Rule = {}
invoke lex&compile(rules, crules, Rule)
part 2
; todo mettre la sub qui suit dans le module lex (? pbm il faut 4/5 params)
declare tok
let tok = {}
sub getToken(tokenList, tokenIndex, tokenNumber, value)
let tokenNumber = tokenList{2, tokenIndex}
if tokenNumber # '' then
declare hexa
let hexa = ''
let hexa = tokenList{1, tokenIndex}
invoke conv&fromHexa(hexa, value)
endif
; si besoin
invoke lex&getToken(tokenList, tokenIndex, tok)
except
endsub
;
echonl "wcalc => + - * / \ % int frac abs neg rnd round0 round1 round2 round3 round4 @pi pop dup clear quit"
;
declare value, stack, token, ind, ruleNumber, ruleValue
let value = ''
let token = ''
let stack = ''
loop
do displayStack(stack)
echo 'wcalc: '
let value = ''
input value
invoke lex&analyze(crules, value, token)
; -----------------------------------------------
; token{1/2/3} en MV : chaine hexa, no token, ordinal_position
let ind = 0
let ruleValue = ''
let ruleNumber = 0
loop
let ind = ind + 1
do getToken(token, ind, ruleNumber, ruleValue)
breakon ruleNumber = ''
continueon ruleNumber = Rule.space
;
if ruleNumber = Rule.other then
echonl 'Syntax error'
break;
; -----------------------------------------------
elseif ruleNumber = Rule.dup then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack = insert(stack, stack{1}, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.pop then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.clear then
let stack = ''
; -----------------------------------------------
elseif ruleNumber = Rule.number or ruleNumber = Rule.integernumber then
if dcount(stack) > 15 then
echonl "Stack full error"
else
let stack = insert(stack, ruleValue, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.random then
if dcount(stack) > 15 then
echonl "Stack full error"
else
declare rnd
let rnd = 0
invoke random&get(rnd)
let stack = insert(stack, rnd, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.varsys then
if dcount(stack) > 15 then
echonl "Stack full error"
else
if ruleValue = '@pi' then
let stack = insert(stack, @pi, 1)
else
echonl "Unknown constant"
endif
endif
; -----------------------------------------------
elseif ruleNumber = Rule.plus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} + stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.minus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} - stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.divide then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} / stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.integerdivide then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} \ stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.modulus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} % stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.multiply then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} * stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.negation then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = neg(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.integer then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = int(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.fractionnal then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = frac(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.absolute then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = abs(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round0 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 0)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round1 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round2 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 2)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round3 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 3)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round4 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 4)
endif
endif
; -----------------------------------------------
breakon ruleNumber = Rule.quit
endloop
breakon ruleNumber = Rule.quit
endloop
echonl "Bye :)"
except
echonl "Exception line ":@exceptline
if @part = 1 then
declare err
let err = 0
invoke lex&error(err)
echonl "lex error : ":err
endif
end
+48
View File
@@ -0,0 +1,48 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
typedef struct {
Dynamic key; /* keeps the keys during cipher/decipher */
} modContextCipher;
/* codes a passer a la fonction setError */
enum {
CIPHER_OK = 0,
CIPHER_KEYLENGTH = 1,
CIPHER_MEM = 2
};
WAPIDECL void cipherInit(env * e, modContextCipher * ctx);
WAPIDECL void cipherEnd(env * e, modContextCipher * ctx);
WAPIDECL long cipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long cipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long cipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
+273
View File
@@ -0,0 +1,273 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "cipher.h"
typedef struct {
int error; // dernier code erreur specifique au module
modContextCipher ctxMod;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
cipherInit(e, &p_etat->ctxMod);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
cipherEnd(e, &p_etat->ctxMod);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toAES128", 8))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramEncrypted = getParam(e, "encrypted", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramEncrypted->type != VAR_DYNAMIC)
var_let(e, paramEncrypted, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, cipher_AES128(e, &p_etat->ctxMod, paramKey, paramPlaintext, paramEncrypted));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromAES128", 10))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramEncrypted = getParam(e, "encrypted", 9);
var * paramPlaintext = getParam(e, "plaintext", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramEncrypted->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, decipher_AES128(e, &p_etat->ctxMod, paramKey, paramEncrypted, paramPlaintext));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "toAES192", 8))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramEncrypted = getParam(e, "encrypted", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramEncrypted->type != VAR_DYNAMIC)
var_let(e, paramEncrypted, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, cipher_AES192(e, &p_etat->ctxMod, paramKey, paramPlaintext, paramEncrypted));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromAES192", 10))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramEncrypted = getParam(e, "encrypted", 9);
var * paramPlaintext = getParam(e, "plaintext", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramEncrypted->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, decipher_AES192(e, &p_etat->ctxMod, paramKey, paramEncrypted, paramPlaintext));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "toAES256", 8))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramEncrypted = getParam(e, "encrypted", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramEncrypted->type != VAR_DYNAMIC)
var_let(e, paramEncrypted, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, cipher_AES256(e, &p_etat->ctxMod, paramKey, paramPlaintext, paramEncrypted));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromAES256", 10))
{
/* get param in the right order */
var * paramKey = getParam(e, "key", 3);
var * paramEncrypted = getParam(e, "encrypted", 9);
var * paramPlaintext = getParam(e, "plaintext", 9);
/* */
if(paramKey == NULL || paramPlaintext == NULL || paramEncrypted == NULL)
exc = EX_MODPARAM;
else if(paramKey->type != VAR_DYNAMIC || paramEncrypted->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
setError(p_etat, decipher_AES256(e, &p_etat->ctxMod, paramKey, paramEncrypted, paramPlaintext));
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+468
View File
@@ -0,0 +1,468 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "cipher.h"
#include "string.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ============ PRIVATE ===================================== */
/* donnees utiles a l'algo aes-128 (travaille sur des blocs de 16 octets)
un "mot" (ou word) est un "int" sur 4 octets
avec une cle sur 16 octets, il y a 4 mots (const NK)
et il y a 10 rondes (const NR)
AES-128 : NK = 4, NR = 10
AES-192 : NK = 6, NR = 12 (les blocs sont toujours de 16 octets)
AES-256 : NK = 8, NR = 14 (les blocs sont toujours de 16 octets)
/!\ ici methode aes-ecb : les blocs chiffres sont independamment les uns des autres => pas le mieux !
methode aes-cbc est meilleure : les blocs dependent les uns des autres (le meme bloc present 2 fois sera chiffre differemment - identiques en ecb !)
*/
#define AES_BLOCKSIZE 16
/* le tableau "cle" a une taille de (4*NK)*(NR+1) */
static octet cle128[(4*4)*(10+1)] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, /* la cle est ici, 16 octets */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, /* filler : va etre calcule ensuite */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
static octet cle192[(4*6)*(12+1)] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, /* la cle est ici, 24 octets */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, /* filler : va etre calcule ensuite */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 };
static octet cle256[(4*8)*(14+1)] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, /* la cle est ici, 32 octets */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32, /* filler : va etre calcule ensuite */
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32 };
/* table utilisee pour la transformation de la cle (expansion), valable pour les les 3 AES 128/192/256 */
static octet rcon[11] = { 0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36 };
/* matrices de substitution utilisee par l'algo : taille 256 */
static octet sbox[256] = { 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16 };
static octet inv_sbox[256] = {0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB,
0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB,
0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E,
0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25,
0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x65,0xB6,0x92,
0x6C,0x70,0x48,0x50,0xFD,0xED,0xB9,0xDA,0x5E,0x15,0x46,0x57,0xA7,0x8D,0x9D,0x84,
0x90,0xD8,0xAB,0x00,0x8C,0xBC,0xD3,0x0A,0xF7,0xE4,0x58,0x05,0xB8,0xB3,0x45,0x06,
0xD0,0x2C,0x1E,0x8F,0xCA,0x3F,0x0F,0x02,0xC1,0xAF,0xBD,0x03,0x01,0x13,0x8A,0x6B,
0x3A,0x91,0x11,0x41,0x4F,0x67,0xDC,0xEA,0x97,0xF2,0xCF,0xCE,0xF0,0xB4,0xE6,0x73,
0x96,0xAC,0x74,0x22,0xE7,0xAD,0x35,0x85,0xE2,0xF9,0x37,0xE8,0x1C,0x75,0xDF,0x6E,
0x47,0xF1,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,0x62,0x0E,0xAA,0x18,0xBE,0x1B,
0xFC,0x56,0x3E,0x4B,0xC6,0xD2,0x79,0x20,0x9A,0xDB,0xC0,0xFE,0x78,0xCD,0x5A,0xF4,
0x1F,0xDD,0xA8,0x33,0x88,0x07,0xC7,0x31,0xB1,0x12,0x10,0x59,0x27,0x80,0xEC,0x5F,
0x60,0x51,0x7F,0xA9,0x19,0xB5,0x4A,0x0D,0x2D,0xE5,0x7A,0x9F,0x93,0xC9,0x9C,0xEF,
0xA0,0xE0,0x3B,0x4D,0xAE,0x2A,0xF5,0xB0,0xC8,0xEB,0xBB,0x3C,0x83,0x53,0x99,0x61,
0x17,0x2B,0x04,0x7E,0xBA,0x77,0xD6,0x26,0xE1,0x69,0x14,0x63,0x55,0x21,0x0C,0x7D };
/* table precalculée pour arithmetique sur les polynomes, taille 256 */
static octet mulx2[256] = { 0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,0x1E,
0x20,0x22,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,0x32,0x34,0x36,0x38,0x3A,0x3C,0x3E,
0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,0x52,0x54,0x56,0x58,0x5A,0x5C,0x5E,
0x60,0x62,0x64,0x66,0x68,0x6A,0x6C,0x6E,0x70,0x72,0x74,0x76,0x78,0x7A,0x7C,0x7E,
0x80,0x82,0x84,0x86,0x88,0x8A,0x8C,0x8E,0x90,0x92,0x94,0x96,0x98,0x9A,0x9C,0x9E,
0xA0,0xA2,0xA4,0xA6,0xA8,0xAA,0xAC,0xAE,0xB0,0xB2,0xB4,0xB6,0xB8,0xBA,0xBC,0xBE,
0xC0,0xC2,0xC4,0xC6,0xC8,0xCA,0xCC,0xCE,0xD0,0xD2,0xD4,0xD6,0xD8,0xDA,0xDC,0xDE,
0xE0,0xE2,0xE4,0xE6,0xE8,0xEA,0xEC,0xEE,0xF0,0xF2,0xF4,0xF6,0xF8,0xFA,0xFC,0xFE,
0x1B,0x19,0x1F,0x1D,0x13,0x11,0x17,0x15,0x0B,0x09,0x0F,0x0D,0x03,0x01,0x07,0x05,
0x3B,0x39,0x3F,0x3D,0x33,0x31,0x37,0x35,0x2B,0x29,0x2F,0x2D,0x23,0x21,0x27,0x25,
0x5B,0x59,0x5F,0x5D,0x53,0x51,0x57,0x55,0x4B,0x49,0x4F,0x4D,0x43,0x41,0x47,0x45,
0x7B,0x79,0x7F,0x7D,0x73,0x71,0x77,0x75,0x6B,0x69,0x6F,0x6D,0x63,0x61,0x67,0x65,
0x9B,0x99,0x9F,0x9D,0x93,0x91,0x97,0x95,0x8B,0x89,0x8F,0x8D,0x83,0x81,0x87,0x85,
0xBB,0xB9,0xBF,0xBD,0xB3,0xB1,0xB7,0xB5,0xAB,0xA9,0xAF,0xAD,0xA3,0xA1,0xA7,0xA5,
0xDB,0xD9,0xDF,0xDD,0xD3,0xD1,0xD7,0xD5,0xCB,0xC9,0xCF,0xCD,0xC3,0xC1,0xC7,0xC5,
0xFB,0xF9,0xFF,0xFD,0xF3,0xF1,0xF7,0xF5,0xEB,0xE9,0xEF,0xED,0xE3,0xE1,0xE7,0xE5 };
/* gestion des polynomes */
static octet mulx3(octet x) { return (mulx2[x]^x); }
static octet mulx9(octet x) { return (mulx2[mulx2[mulx2[x]]]^x); }
static octet mulx11(octet x) { return (mulx2[mulx2[mulx2[x]]^x]^x); }
static octet mulx13(octet x) { return (mulx2[mulx2[mulx2[x]^x]]^x); }
static octet mulx14(octet x) { return (mulx2[mulx2[mulx2[x]^x]^x]); }
static void initCleExpansion(env * e, octet * baseKey, octet * key, int NK, int NR)
{
/* copie cle de base dans les cles de rondes */
memcopie(key, baseKey, NK*4);
/* creation des cles de rondes a partir de la cle "de base" */
octet tmp[4], t; /* travail octet par octet */
int n; /* compteur */
for(n = NK*4; n < (4*NK)*(NR+1); n += 4)
{
/* boucle principale de remplissage de la table des cles */
tmp[0] = key[n-4];
tmp[1] = key[n-3];
tmp[2] = key[n-2];
tmp[3] = key[n-1];
if(n % (NK * 4) == 0)
{
/* tous les NK mots, transformation a faire */
/* rotation a gauche de tmp */
t = tmp[0];
tmp[0] = tmp[1];
tmp[1] = tmp[2];
tmp[2] = tmp[3];
tmp[3] = t;
/* application de la transco s-box */
tmp[0] = sbox[tmp[0]];
tmp[1] = sbox[tmp[1]];
tmp[2] = sbox[tmp[2]];
tmp[3] = sbox[tmp[3]];
/* transformation avec les "round constant" */
tmp[0] ^= rcon[n/(4*NK)];
}
else if(NK > 6 && (n % (NK * 4)) == 16)
{
/* AES256 */
tmp[0] = sbox[tmp[0]];
tmp[1] = sbox[tmp[1]];
tmp[2] = sbox[tmp[2]];
tmp[3] = sbox[tmp[3]];
}
key[n] = (key[n-4*NK] ^ tmp[0]);
key[n+1] = (key[n-4*NK+1] ^ tmp[1]);
key[n+2] = (key[n-4*NK+2] ^ tmp[2]);
key[n+3] = (key[n-4*NK+3] ^ tmp[3]);
}
}
void cipher(env * e, octet * cle, int NK, int NR, var * in, var * out)
{
/* chiffrer par blocs de 16 octets (AES_BLOCKSIZE) */
pointeur tIn = in->ptr, tOut;
int r; /* no de ronde */
int n; /* compteur */
octet t0, t1, t2, t3;
int nbblock = in->mLg / AES_BLOCKSIZE, lastblock = 0, cptblock, rest = in->mLg % AES_BLOCKSIZE;
octet pad = AES_BLOCKSIZE - rest; /* <pad> = nb octets ajoutes a la fin, de 1 a 16 (1 a AES_BLOCKSIZE)*/
lastblock = ++nbblock;
/* */
if(dynCtrl(e, out, in->mLg + (ent64)pad, FALSE) != DYN_OK)
return;
tOut = out->ptr;
/* */
for(cptblock = 1; cptblock <= nbblock; cptblock++)
{
if(cptblock == lastblock)
{
for(n = 0; n < rest; n++)
tOut[n] = (tIn[n] ^ cle[n]);
for(n = rest; n < AES_BLOCKSIZE; n++)
tOut[n] = (pad ^ cle[n]);
}
else
/* tInitialisation de la sortie par une transfo "RoundKeyValue" */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = (tIn[n] ^ cle[n]);
/* traitement des NR rondes */
for(r = 1; r <= NR; r++)
{
/* etape "SubBytes" transco s-box */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = sbox[tOut[n]];
/* etape "ShiftRows" : decalage "a gauche" des lignes 2 3 4 de 1 2 3 positions */
t0 = tOut[1];
tOut[1] = tOut[5];
tOut[5] = tOut[9];
tOut[9] = tOut[13];
tOut[13] = t0;
/**/
t0 = tOut[2];
tOut[2] = tOut[10];
tOut[10] = t0;
t0 = tOut[6];
tOut[6] = tOut[14];
tOut[14] = t0;
/**/
t0 = tOut[15];
tOut[15] = tOut[11];
tOut[11] = tOut[7];
tOut[7] = tOut[3];
tOut[3] = t0;
/* etape "MixColumns" sauf derniere ronde */
if(r < NR)
for(n = 0; n < AES_BLOCKSIZE; n+=4)
{
t0 = (mulx2[tOut[n]] ^ tOut[n+3] ^ tOut[n+2] ^ mulx3(tOut[n+1])); /* 2*a0 + a3 + a2 + 3*a1 */
t1 = (mulx2[tOut[n+1]] ^ tOut[n] ^ tOut[n+3] ^ mulx3(tOut[n+2])); /* 2*a1 + a0 + a3 + 3*a2 */
t2 = (mulx2[tOut[n+2]] ^ tOut[n+1] ^ tOut[n] ^ mulx3(tOut[n+3])); /* 2*a2 + a1 + a0 + 3*a3 */
t3 = (mulx2[tOut[n+3]] ^ tOut[n+2] ^ tOut[n+1] ^ mulx3(tOut[n])); /* 2*a3 + a2 + a1 + 3*a0 */
tOut[n] = t0;
tOut[n+1] = t1;
tOut[n+2] = t2;
tOut[n+3] = t3;
}
/* etape "RoundKeyValue" */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] ^= cle[n + r * AES_BLOCKSIZE];
}
tIn += AES_BLOCKSIZE;
tOut += AES_BLOCKSIZE;
}
dynSetLen(e, out, in->mLg + (ent64)pad);
}
void decipher(env * e, octet * cle, int NK, int NR, var * in, var * out)
{
/* dechiffrer par blocs de 16 octets (AES_BLOCKSIZE) */
pointeur tIn = in->ptr, tOut;
if(in->mLg == 0 || in->mLg % AES_BLOCKSIZE != 0)
return; /* chiffre forcement multiple de 16 (AES_BLOCKSIZE) */
if(dynCtrl(e, out, in->mLg, FALSE) != DYN_OK)
return;
tOut = out->ptr;
int r; /* no de ronde */
int n; /* compteur */
octet t0, t1, t2, t3;
int nbblock = in->mLg / (AES_BLOCKSIZE), cptblock;
/* */
for(cptblock = 1; cptblock <= nbblock; cptblock++)
{
/* tInitialisation de la sortie par une transfo "RoundKeyValue" */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = (tIn[n] ^ cle[n + NR * AES_BLOCKSIZE]);
/* traitement des NR rondes */
for(r = NR-1; r >= 0; r--)
{
/* etape "tInvShiftRows" : decalage a droite sur lignes 2 3 4 de 1 2 3 positions */
t0 = tOut[13];
tOut[13] = tOut[9];
tOut[9] = tOut[5];
tOut[5] = tOut[1];
tOut[1] = t0;
/**/
t0 = tOut[2];
tOut[2] = tOut[10];
tOut[10] = t0;
t0 = tOut[6];
tOut[6] = tOut[14];
tOut[14] = t0;
/**/
t0 = tOut[3];
tOut[3] = tOut[7];
tOut[7] = tOut[11];
tOut[11] = tOut[15];
tOut[15] = t0;
/* etape "tInvSubBytes" transco tInv s-box */
for(n = 0; n < AES_BLOCKSIZE; n++)
tOut[n] = inv_sbox[tOut[n]];
/* etape "RoundKeyValue" */
for(n = 0;n < AES_BLOCKSIZE; n++)
tOut[n] ^= cle[n + r * AES_BLOCKSIZE];
/* etape "tInvMixColumns" sauf derniere ronde */
if(r > 0)
for(n = 0; n < AES_BLOCKSIZE; n+=4)
{
t0 = (mulx14(tOut[n]) ^ mulx9(tOut[n+3]) ^ mulx13(tOut[n+2]) ^ mulx11(tOut[n+1])) ; /* 14*a0 + 9*a3 + 13*a2 + 11*a1 */
t1 = (mulx14(tOut[n+1]) ^ mulx9(tOut[n]) ^ mulx13(tOut[n+3]) ^ mulx11(tOut[n+2])) ; /* 14*a1 + 9*a0 + 13*a3 + 11*a2 */
t2 = (mulx14(tOut[n+2]) ^ mulx9(tOut[n+1]) ^ mulx13(tOut[n]) ^ mulx11(tOut[n+3])) ; /* 14*a2 + 9*a1 + 13*a0 + 11*a3 */
t3 = (mulx14(tOut[n+3]) ^ mulx9(tOut[n+2]) ^ mulx13(tOut[n+1]) ^ mulx11(tOut[n])) ; /* 14*a3 + 9*a2 + 13*a1 + 11*a0 */
tOut[n] = t0;
tOut[n+1] = t1;
tOut[n+2] = t2;
tOut[n+3] = t3;
}
}
tIn += AES_BLOCKSIZE;
tOut += AES_BLOCKSIZE;
}
/* enlever a la longueur finale le padding */
octet pad = out->ptr[in->mLg - 1];
if(pad < 1 || pad > AES_BLOCKSIZE)
pad = 0; /* padding incorrect */
dynSetLen(e, out, in->mLg - (ent64)(pad));
}
/* ============ PUBLIC ===================================== */
WAPIDECL void cipherInit(env * e, modContextCipher * ctx)
{
dynInit(e, &ctx->key, 512);
}
WAPIDECL void cipherEnd(env * e, modContextCipher * ctx)
{
dynFree(e, &ctx->key);
}
WAPIDECL long cipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*4)*(10+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*4)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle128, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 4, 10); /* cle128 */
cipher(e, ctx->key.ptr, 4, 10, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long cipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*6)*(12+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*6)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle192, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 6, 12); /* cle192 */
cipher(e, ctx->key.ptr, 6, 12, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long cipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*8)*(14+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*8)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle256, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 8, 14); /* cle256 */
cipher(e, ctx->key.ptr, 8, 14, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long decipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*4)*(10+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*4)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle128, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 4, 10); /* cle128 */
decipher(e, ctx->key.ptr, 4, 10, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long decipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*6)*(12+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*6)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle192, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 6, 12); /* cle192 */
decipher(e, ctx->key.ptr, 6, 12, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
WAPIDECL long decipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out)
{
long lg = (4*8)*(14+1);
/* controle longueur cle + copie octets des cles de rondes */
if(cle->mLg != 4*8)
return CIPHER_KEYLENGTH;
if(dynCtrl(e, &ctx->key, lg, FALSE))
return CIPHER_MEM;
memcopie(ctx->key.ptr, cle256, lg);
dynSetLen(e, &ctx->key, lg);
/* */
initCleExpansion(e, cle->ptr, ctx->key.ptr, 8, 14); /* cle256 */
decipher(e, ctx->key.ptr, 8, 14, in, out);
/* */
memset(ctx->key.ptr, 0, ctx->key.mLgmax);
return CIPHER_OK;
}
+58 -18
View File
@@ -1,42 +1,71 @@
BUILD=`date +%Y%m%d%H%M%S`
echo BUILD $BUILD
echo 0. Compilation pour shared lib
gcc -c w_src/dynamic.c -s -Wall -DUNIX -m64 -fPIC -o exec/dynamic.o -Wno-unused-value
gcc -c w_src/var.c -s -Wall -DUNIX -m64 -fPIC -o exec/var.o
gcc -c w_src/hashtable.c -s -Wall -DUNIX -m64 -fPIC -o exec/hashtable.o
gcc -c w_src/buffer.c -s -Wall -DUNIX -m64 -fPIC -o exec/buffer.o
gcc -c w_src/global.c -s -Wall -DUNIX -m64 -fPIC -o exec/global.o
gcc -c w_src/rep.c -s -Wall -DUNIX -m64 -fPIC -o exec/rep.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o -o exec/libw.so
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o
gcc -c w_src/lex.c -s -Wall -DUNIX -m64 -fPIC -o exec/lexw.o
gcc -c w_src/convert.c -s -Wall -DUNIX -m64 -fPIC -o exec/convert.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o exec/lexw.o exec/convert.o -o exec/libw.so
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o exec/lexw.o exec/convert.o
echo 1. Compilation de modeleMod.c
gcc -shared -s -o exec/modele.o w_src/modeleMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 1. Compilation de templateMod.c
gcc -shared -s -o exec/template.o w_src/templateMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 2. Compilation de fileMod.c
gcc -shared -s -o exec/file.o w_src/fileMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 3. Compilation de sockMod.c
gcc -shared -s -o exec/sock.o w_src/sockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/sock_lib.so w_src/sock_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/sock.o w_src/sockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:sock_lib.so
echo 4. Compilation de dbMod.c et dbpgsql.c
gcc -shared -s -o exec/db.o w_src/dbMod.c -m64 -DUNIX -Wall -ldl -fPIC -L./exec -l:libw.so
echo 3b. Compilation de securesockMod.c
gcc -shared -s -o exec/securesock_lib.so w_src/securesock_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -lssl -lcrypto -l:sock_lib.so
gcc -shared -s -o exec/securesock.o w_src/securesockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:securesock_lib.so
echo 3c. Compilation de sshMod.c
gcc -shared -s -o exec/wssh_lib.so w_src/ssh_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -lssl -lcrypto -lssh
gcc -shared -s -o exec/wssh.o w_src/sshMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:wssh_lib.so
#echo 4. Compilation de sqlite
#gcc -shared -s -o exec/db.o w_src/dbMod.c -m64 -DUNIX -Wall -ldl -fPIC -L./exec -l:libw.so
#gcc -shared -s -o exec/pgsql.o w_src/dbpgsql.c -m64 -DUNIX -Wall -I/usr/include/postgresql -fPIC -L./exec -l:libw.so
#gcc -shared -s -o exec/libsqlite3.so w_src/sqlite3.c -m64 -fPIC -lpthread -ldl -lm
gcc -shared -s -o exec/sqlite_lib.so w_src/sqlite_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 4. Compilation de convdMod.c
gcc -shared -s -o exec/conv.o w_src/convMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 5. Compilation de lzwMod.c
gcc -shared -s -o exec/lzw_lib.o w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/lzw.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:lzw_lib.o
gcc -shared -s -o exec/lzw_lib.so w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/lzw.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:lzw_lib.so
echo 5. Compilation de pdfMod.c
gcc -shared -s -o exec/pdf_lib.o w_src/pdf_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
#gcc -shared -s -o exec/pdf.o w_src/pdfMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:pdf_lib.o
gcc -shared -s -o exec/pdf_lib.so w_src/pdf_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/pdf.o w_src/pdfMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:pdf_lib.so -l:lzw_lib.so
echo 6. Compilation de jsonMod.c
gcc -shared -s -o exec/json_lib.o w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.o
gcc -shared -s -o exec/json_lib.so w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.so
echo 6. Compilation de shmMod.c
gcc -shared -s -o exec/shm_lib.so w_src/shm_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/shm.o w_src/shmMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:shm_lib.so
echo 7. Compilation de timeMod.c
gcc -shared -s -o exec/time.o w_src/timeMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 8. Compilation de hashMod.c
gcc -shared -s -o exec/hash.o w_src/hashMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/hash_lib.so w_src/hash_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/hash.o w_src/hashMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:hash_lib.so
echo 8b. Compilation de cipherMod.c
gcc -shared -s -o exec/cipher_lib.so w_src/cipher_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/cipher.o w_src/cipherMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:cipher_lib.so
echo 9. Compilation de systemMod.c
gcc -shared -s -o exec/system.o w_src/systemMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
@@ -44,11 +73,22 @@ gcc -shared -s -o exec/system.o w_src/systemMod.c -m64 -DUNIX -Wall -fPIC -L./ex
echo 10. Compilation de randomMod.c
gcc -shared -s -o exec/random.o w_src/randomMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 10b. Compilation de lexMod.c
gcc -shared -s -o exec/lex.o w_src/lexMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 10c. Compilation de fastcgi/http/raw/websocket
gcc -shared -s -o exec/raw_lib.so w_src/raw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/fcgi_lib.so w_src/fcgi_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/http_lib.so w_src/http_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/websocket_lib.so w_src/websocket_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/http.o w_src/httpMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:http_lib.so
gcc -shared -s -o exec/fcgi.o w_src/fcgiMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:fcgi_lib.so
echo 11. Compilation et link de langage.c
gcc w_src/langage.c -s -o exec/lw -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so
gcc w_src/langage.c -s -o exec/lw -ldl -m64 -DUNIX -DBUILD=$BUILD -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:shm_lib.so -l:lzw_lib.so
echo 12. Compilation et link de assembler.c
gcc w_src/assembler.c -s -o exec/lwa -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so
gcc w_src/assembler.c -s -o exec/lwa -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:lzw_lib.so
echo 13. Generation du formatteur de code
gcc w_src/format.c -s -o exec/lwf -Wall -m64 -DUNIX -L./exec -l:libw.so
@@ -59,7 +99,7 @@ gcc w_src/genlex.c -o exec/wlex -s -Wall -m64 -DUNIX -L./exec -l:libw.so
echo 15. Generation de l\'analyseur de source w \(compilateur w\)
gcc w_src/genw.c -s -o exec/lwc -Wall -m64 -DUNIX -Wno-stringop-truncation -L./exec -l:libw.so
echo "test_utf => gcc test_utf.c -s -o utf -Wall -m64 -DUNIX -L./exec -l:libw.so"
echo "test_pdf => gcc test_pdf.c -s -o pdf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:pdf_lib.o -l:lzw_lib.o"
echo "test_utf => gcc test_utf.c -s -o utf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:lzw_lib.so"
echo "test_pdf => gcc test_pdf.c -s -o pdf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:pdf_lib.so -l:lzw_lib.so"
echo "package => dpkg-deb --build wlanguage"
+83 -59
View File
@@ -5,81 +5,105 @@ call vcvars64.bat
cd "C:\Users\Poupougne42\source\repos\win_w_src"
echo 0. Compilation pour static lib
cl /c /Foexec\dynamic.obj w_src\dynamic.c
cl /c /Foexec\var.obj w_src\var.c
cl /c /Foexec\hashtable.obj w_src\hashtable.c
cl /c /Foexec\global.obj w_src\global.c
cl /c /Foexec\rep.obj w_src\rep.c
echo ------------------------------------------------------------------------------------------
echo 0. Compilation pour dynamic lib DLL
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\libw.dll w_src\dynamic.c w_src\var.c w_src\hashtable.c w_src\buffer.c w_src\global.c w_src\rep.c w_src\lex.c w_src\convert.c /DEBUG:NONE
echo 1a. Compilation de templateMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\template.dll w_src\templateMod.c exec\libw.lib /DEBUG:NONE
lib /OUT:exec\libw.lib exec\dynamic.obj exec\var.obj exec\hashtable.obj exec\global.obj exec\rep.obj
echo ------------------------------------------------------------------------
echo 1a. Compilation de modeleMod.c
cl w_src\modeleMod.c exec\libw.lib /Foexec\modeleMod.obj /DWINLIB /link /DLL /OUT:exec\modele.dll
echo ------------------------------------------------------------------------
echo 1b. Compilation de fileMod.c
cl w_src\fileMod.c exec\libw.lib /Foexec\fileMod.obj /DWINLIB /link /DLL /OUT:exec\file.dll
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\file.dll w_src\fileMod.c exec\libw.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 1c. Compilation de jsonMod.c
cl /c /Foexec\json_lib.obj w_src\json_lib.c
lib /OUT:exec\json_lib.lib exec\json_lib.obj
cl w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /Foexec\jsonMod.obj /DWINLIB /link /DLL /OUT:exec\json.dll
echo 1c. Compilation de timeMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\time.dll w_src\timeMod.c exec\libw.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 1d. Compilation de timeMod.c
cl w_src\timeMod.c exec\libw.lib /Foexec\timeMod.obj /DWINLIB /link /DLL /OUT:exec\time.dll
echo 1d. Compilation de hashMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\hash_lib.dll w_src\hash_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\hash.dll w_src\hashMod.c exec\libw.lib exec\hash_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 1e. Compilation de hashMod.c
cl w_src\hashMod.c exec\libw.lib /Foexec\hashMod.obj /DWINLIB /link /DLL /OUT:exec\hash.dll
echo 1e. Compilation de systemMod.c (ws2_32.lib pour socket)
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\system.dll w_src\systemMod.c exec\libw.lib ws2_32.lib advapi32.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 1f. Compilation de systemMod.c
cl w_src\systemMod.c exec\libw.lib ws2_32.lib /Foexec\systemMod.obj /DWINLIB /link /DLL /OUT:exec\system.dll
echo 1f. Compilation de randomMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\random.dll w_src\randomMod.c exec\libw.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 1g. Compilation de randomMod.c
cl w_src\randomMod.c exec\libw.lib /Foexec\randomMod.obj /DWINLIB /link /DLL /OUT:exec\random.dll
echo ------------------------------------------------------------------------
echo 1h. Compilation de lzwMod.c
cl /c /Foexec\lzw_lib.obj w_src\lzw_lib.c
lib /OUT:exec\lzw_lib.lib exec\lzw_lib.obj
cl w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib /Foexec\lzwMod.obj /DWINLIB /link /DLL /OUT:exec\lzw.dll
echo ------------------------------------------------------------------------
echo 1h. Compilation de pdfMod.c
cl /c /Foexec\pdf_lib.obj w_src\pdf_lib.c
lib /OUT:exec\pdf_lib.lib exec\pdf_lib.obj
rem cl w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib /Foexec\pdfMod.obj /DWINLIB /link /DLL /OUT:exec\pdf.dll
echo 1g. Compilation de cipherMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\cipher_lib.dll w_src\cipher_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\cipher.dll w_src\cipherMod.c exec\libw.lib exec\cipher_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 2. Compilation langage lw (ws2_32.lib pour socket)
cl w_src\langage.c exec\libw.lib ws2_32.lib /Foexec\langage.obj /DWINLIB /link /OUT:exec\lw.exe
echo ------------------------------------------------------------------------------------------
echo 2a. Compilation de jsonMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\json_lib.dll w_src\json_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 3. Compilation assembleur lwa
cl w_src\assembler.c exec\libw.lib /Foexec\assembler.obj /DWINLIB /link /OUT:exec\lwa.exe
echo 2b. Compilation de shmMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\shm_lib.dll w_src\shm_lib.c exec\libw.lib advapi32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\shm.dll w_src\shmMod.c exec\libw.lib exec\shm_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 4. Compilation du compilateur W (generateur d'assembleur)
cl w_src\genw.c exec\libw.lib /Foexec\genw.obj /DWINLIB /link /OUT:exec\lwc.exe
echo 2c. Compilation de lzwMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\lzw_lib.dll w_src\lzw_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lzw.dll w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 5. Compilation formatteur de code w
cl w_src\format.c exec\libw.lib /Foexec\format.obj /DWINLIB /link /OUT:exec\lwf.exe
echo 2d. Compilation de pdfMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\pdf_lib.dll w_src\pdf_lib.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\pdf.dll w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------
echo 6. Generation du generateur de fichier lex
cl w_src\genlex.c exec\libw.lib /Foexec\genlex.obj /DWINLIB /link /OUT:exec\wlex.exe
echo 2e. Compilation de sockMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sock_lib.dll w_src\sock_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\sock.dll w_src\sockMod.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE
rem purge des .obj
echo 2eb. Compilation de securesockMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\securesock_lib.dll w_src\securesock_lib.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" libssl.lib libcrypto.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\securesock.dll w_src\securesockMod.c exec\libw.lib exec\sock_lib.lib exec\securesock_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include"
echo 2ec. Compilation de sshMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\wssh_lib.dll w_src\ssh_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" ssh.lib libssl.lib libcrypto.lib z.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\wssh.dll w_src\sshMod.c exec\libw.lib exec\wssh_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" ssh.lib libssl.lib libcrypto.lib z.lib
echo 2f. Compilation de convMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\conv.dll w_src\convMod.c exec\libw.lib /DEBUG:NONE
echo 2g. Compilation de lexMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lex.dll w_src\lexMod.c exec\libw.lib /DEBUG:NONE
echo 2h. Compilation de fcgi.c/http.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\raw_lib.dll w_src\raw_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\fcgi_lib.dll w_src\fcgi_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\http_lib.dll w_src\http_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\websocket_lib.dll w_src\websocket_lib.c exec\libw.lib exec\hash_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\http.dll w_src\httpMod.c exec\libw.lib exec\http_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\fcgi.dll w_src\fcgiMod.c exec\libw.lib exec\fcgi_lib.lib /DEBUG:NONE
echo 2i. Compilation de sqlite
cl /LD /Gy /MD /Feexec\sqlite3.dll w_src\sqlite3.c /DSQLITE_API=__declspec(dllexport) /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sqlite_lib.dll w_src\sqlite_lib.c exec\libw.lib exec\sqlite3.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 3a. Generation lw.exe
cl w_src\langage.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lw.exe exec\libw.lib exec\shm_lib.lib exec\lzw_lib.lib advapi32.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3b. Generation lwa.exe
cl w_src\assembler.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwa.exe exec\libw.lib exec\lzw_lib.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3c. Generation lwc.exe
cl w_src\genw.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwc.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3d. Generation lwf.exe
cl w_src\format.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwf.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3d. Generation wlex.exe
cl w_src\genlex.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\wlex.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
rem echo 3e. Generation test.exe
rem cl w_src\test.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\test.exe exec\libw.lib exec\encod_lib.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo ------------------------------------------------------------------------------------------
echo 4. Purge
del .\*.obj
del exec\*.obj
del exec\*.lib
del exec\*.exp
dir exec
exit
+231
View File
@@ -0,0 +1,231 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "convert.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_CONVFMT = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Conversion error, bad character"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toHexa", 6))
{
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHexadecimal = getParam(e, "hexadecimal", 11);
if(paramPlaintext == NULL || paramHexadecimal == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramHexadecimal->type != VAR_DYNAMIC)
var_let(e, paramHexadecimal, &e->int_dynamic, FALSE, FALSE);
if(str2hex(e, paramPlaintext, paramHexadecimal) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromHexa", 8))
{
/* get param in the right order */
var * paramHexadecimal = getParam(e, "hexadecimal", 11);
var * paramPlaintext = getParam(e, "plaintext", 9);
if(paramHexadecimal == NULL || paramPlaintext == NULL)
exc = EX_MODPARAM;
else if(paramHexadecimal->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
if(hex2str(e, paramHexadecimal, paramPlaintext) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "toBase64", 8))
{
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramBase64encoded = getParam(e, "base64encoded", 13);
if(paramPlaintext == NULL || paramBase64encoded == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramBase64encoded->type != VAR_DYNAMIC)
var_let(e, paramBase64encoded, &e->int_dynamic, FALSE, FALSE);
if(str2base64(e, paramPlaintext, paramBase64encoded) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromBase64", 10))
{
/* get param in the right order */
var * paramBase64encoded = getParam(e, "base64encoded", 13);
var * paramPlaintext = getParam(e, "plaintext", 9);
if(paramBase64encoded == NULL || paramPlaintext == NULL)
exc = EX_MODPARAM;
else if(paramBase64encoded->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPlaintext->type != VAR_DYNAMIC)
var_let(e, paramPlaintext, &e->int_dynamic, FALSE, FALSE);
if(base642str(e, paramBase64encoded, paramPlaintext) != DYN_OK)
exc = setError(p_etat, EXMOD_CONVFMT);
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+276
View File
@@ -0,0 +1,276 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "langage.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/* ****** PRIVATE ************************ */
static char hexa[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 128 cars a la fin de cette ligne */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
static char carhex[16] = {"0123456789abcdef"};
static char base64[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* '+' = 62 ; '/' = 63 ; '-' (62) se trouve au milieu entre les deux */
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,99,-1,-1, /* '=' mis a 99 */
-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* dernier -1 ici = '_' (63) */
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 128 cars a la fin de cette ligne */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; // "=" mis a 99
static char carBase64[65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}; /* et caractere "=" en complement */
// TODO static char carBase64url[65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="}; /* et caractere "=" en complement */
/* TODO compatible UTF8 !! */
/* ****** PUBLIC ************************ */
WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat)
{
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
if(dynCtrl(e, resultat, this->mLg * 2, DYN_FALSE)) /* chaine hexa : taille double de celle origine */
return DYN_ERR;
long from = this->mLg - 1;
long to = from * 2 + 1;
/* cette methode fonctionne aussi si this et resultat pointent sur la meme variable... mettre TRUE dans dynCtrl alors ! */
for( ;from >= 0; )
{
resultat->ptr[to--] = carhex[this->ptr[from] % 16];
resultat->ptr[to--] = carhex[this->ptr[from--] / 16];
}
dynSetLen(e, resultat, this->mLg * 2);
return DYN_OK;
}
WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat)
{
/* conversion en base64 /base64url */
/* 3 cars en clair en donne 4 en base 64 ; si le dernier bloc contient 2 cars, la sortie est de 3 cars */
/* + car "=" ; si le dernier bloc contient 1 car, la sortie est de 2 cars + deux cars "=" */
/* quand le dernier bloc contient 1 ou 2 cars, les bits manquants pour avoir des octets complets sont mis a 0 */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
/* */
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
long lg64 = this->mLg / 3;
if(this->mLg % 3 != 0)
lg64++;
lg64 *= 4; // longueur finale du base64
if(dynCtrl(e, resultat, lg64, DYN_FALSE))
return DYN_ERR;
/* */
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 3)
{
if(from + 1 >= this->mLg)
{
/* bloc de 1 octet => 2 cars en sortie + 2 cars de complement */
resultat->mPtr[to++] = carBase64[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4)];
resultat->mPtr[to++] = carBase64[64];
resultat->mPtr[to++] = carBase64[64];
/* */
} else if(from + 2 >= this->mLg)
{
/* bloc de 2 octets => 3 cars en sortie + 1 car en complement */
resultat->mPtr[to++] = carBase64[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4) | (this->ptr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->ptr[from + 1] & 15) << 2)];
resultat->mPtr[to++] = carBase64[64];
}
else
{
/* bloc de 3 octets => 4 cars en sortie */
resultat->mPtr[to++] = carBase64[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4) | (this->ptr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->ptr[from + 1] & 15) << 2) | (this->ptr[from + 2] >> 6)];
resultat->mPtr[to++] = carBase64[this->ptr[from + 2] & 63];
}
}
/* */
dynSetLen(e, resultat, lg64);
return DYN_OK;
}
WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat)
{
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
if(this->mLg % 2 != 0)
return DYN_ERR; /* erreur format hexa incorrect */
if(dynCtrl(e, resultat, this->mLg / 2, DYN_FALSE))
return DYN_ERR;
/* */
char c1, c2;
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 2)
{
if((c1 = hexa[this->ptr[from]]) == -1 || (c2 = hexa[this->ptr[from + 1]]) == -1)
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* erreur format hexa incorrect */
}
resultat->ptr[to++] = (c1 << 4) | c2;
}
dynSetLen(e, resultat, this->mLg / 2);
return DYN_OK;
}
WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat)
{
/* conversion en clair de la chaine en base64 */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
if(this->mLg == 0)
{
dynSetLen(e, resultat, 0);
return DYN_OK;
}
if(this->mLg % 4 != 0)
return DYN_ERR; /* erreur format base64 incorrect */
long lgClair = (this->mLg / 4) * 3;
if(dynCtrl(e, resultat, lgClair, DYN_FALSE))
return DYN_ERR;
/* */
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 4, to += 3)
{
char c1 = base64[this->ptr[from]];
char c2 = base64[this->ptr[from + 1]];
char c3 = base64[this->ptr[from + 2]];
char c4 = base64[this->ptr[from + 3]];
if(c1 == -1 || c2 == -1 || c3 == -1 || c4 == -1 || c1 == 99 || c2 == 99 || (c3 == 99 && c4 != 99))
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* erreur format base64 incorrect */
}
if(c4 == 99 && from + 4 < this->mLg)
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* '=' autorise en fin de chaine uniquement */
}
//
resultat->ptr[to] = 0;
resultat->ptr[to + 1] = 0;
resultat->ptr[to + 2] = 0;
resultat->ptr[to] = c1 << 2;
resultat->ptr[to] |= c2 >> 4;
if(c3 != 99)
{
resultat->ptr[to + 1] = (c2 & 15) << 4;
resultat->ptr[to + 1] |= c3 >> 2;
if(c4 != 99)
{
resultat->ptr[to + 2] = (c3 & 3) << 6;
resultat->ptr[to + 2] |= c4;
}
else
lgClair--;
}
else
lgClair--;
}
dynSetLen(e, resultat, lgClair);
return DYN_OK;
}
WAPIDECL void str2upper(env * e, Dynamic * this)
{
long i;
for(i = 0; i < this->mLg; i++)
if(this->mPtr[i] >= 'a' && this->mPtr[i] <= 'z')
this->mPtr[i] -= 32;
}
WAPIDECL void str2lower(env * e, Dynamic * this)
{
long i;
for(i = 0; i < this->mLg; i++)
if(this->mPtr[i] >= 'A' && this->mPtr[i] <= 'Z')
this->mPtr[i] += 32;
}
WAPIDECL ent64s hex2num(env * e, Dynamic * this)
{
ent64s resultat = 0;
char c;
long i;
for(i = 0; i < this->mLg; i++)
if((c = hexa[this->ptr[i]]) == -1)
break; // erreur hexa : fin de la conversion
else
resultat = (resultat << 4) + (ent64s)c;
return resultat;
}
+36
View File
@@ -0,0 +1,36 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifndef CONVERT_H
#define CONVERT_H
#include "dynamic.h"
WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL void str2upper(env * e, Dynamic * this);
WAPIDECL void str2lower(env * e, Dynamic * this);
WAPIDECL ent64s hex2num(env * e, Dynamic * this);
#endif
+44 -30
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -77,16 +77,24 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -97,43 +105,49 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
memset(p_etat->base, 0, LGNOMBASE + 1);
p_etat->ctx = NULL;
p_etat->fnDb = NULL;
//
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
//*** code specifique ici
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "conn", 4) == 0)
else if(modFnIs(e, "conn", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -182,7 +196,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "disc", 4) == 0)
else if(modFnIs(e, "disc", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -208,7 +222,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "info", 4) == 0)
else if(modFnIs(e, "info", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
+9 -9
View File
@@ -221,7 +221,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
// -----------------------------------------------------------
if(strncmp(e->fn, "read", 4) == 0)
if(modFnIs(e, "read", 4))
{
// param<1> = no fichier ; param<2> = cle
dynRemove(e, param, &p_etat->mTmp, cFM, DYN_TRUE);
@@ -319,11 +319,11 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
return EX_DB_ELSE; // pas d'erreur : mettre le code pour "non trouve" ELSE
}
}
else if(strncmp(e->fn, "write", 4) == 0)
else if(modFnIs(e, "write", 5))
{
//
}
else if(strncmp(e->fn, "open", 4) == 0)
else if(modFnIs(e, "open", 4))
{
// param<1> = nom table ; si ok renvoie en retour param<1> = id fichier (indice du tableau)
int lgSav = p_etat->mBase.mLg;
@@ -376,7 +376,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
dynSetLen(e, &p_etat->mBase, lgSav);
}
else if(strncmp(e->fn, "create", 5) == 0)
else if(modFnIs(e, "create", 5))
{
// cree la table : param<1> nom ; modulo param<2> ; separateur param<3>
fileHeader info;
@@ -421,7 +421,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
}
else if(strncmp(e->fn, "close", 5) == 0)
else if(modFnIs(e, "close", 5))
{
// param<1> = no fichier
int pos = dynToNum(e, param, 0, 6);
@@ -437,7 +437,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
// sinon, fichier deja ferme : RAS
}
}
else if(strncmp(e->fn, "setup", 5) == 0)
else if(modFnIs(e, "setup", 5))
{
// sortir si mId deja present (!=0) : une base est deja ouverte
// param<1> = repertoire de base => sa cle d'acces = mKey
@@ -488,7 +488,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
}
}
}
else if(strncmp(e->fn, "init", 4) == 0)
else if(modFnIs(e, "init", 4))
{
// si init deja fait, ras
if(p_etat == NULL)
@@ -502,7 +502,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
dynInit(e, &p_etat->mEntry, DYN_LGMIN);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
struct shmid_ds attrs = {0};
// liberation specifique au module avant arret process
@@ -534,7 +534,7 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
memfree(e, p_etat);
*etat = NULL;
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
dynLet(e, param, "100", 3); // version 1.00 ici
+542 -248
View File
File diff suppressed because it is too large. Load diff
+3 -1
View File
@@ -5,5 +5,7 @@ aide: (1,1,?)
nombre: (1,9,0-9)
ajouter: (1,1,#2B) ; +
supprimer:(1,1,#2D) ; -
ident: (1,1,#3A) (1,1,a-zA-Z_) (0,23,a-zA-Z0-9) ; :abcABC123
ident: (1,1,#3A) (1,1,a-zA-Z_) (0,23,a-zA-Z0-9) ; :_abcABC123
identnext:(1,1,#2E) (1,1,a-zA-Z) (0,23,a-zA-Z0-9) ; .abcABC123
reste: (1,1,#00-#FF)
+99
View File
@@ -0,0 +1,99 @@
;
; for background w process debugging
; using shm_lib on buffer "dbg<pid>" for the debugged process
; Usage: lw debug <pid2debug>
;
begin wdebug
declare idProc, msg, pid, cmd, ret, capt, again, delay, debugging, signal
declare OK, ERROR
let debugging = @false
let OK = 0
let ERROR = neg(1)
;
sub WriteProcess(id, message, cr)
invoke shm&set(id, message)
let cr = OK
except
let cr = ERROR
catch
endsub
;
sub ReadProcess(message, cr)
invoke shm&get(message)
let cr = OK
except
let cr = ERROR
catch
endsub
; ********************************************************
;
let pid = field(@arg, @currfm, 2)
if pid = '' or type(pid) # @varnumber then
let msg = 'Incorrect pid number (':pid:'), abort'
echonl msg
return
endif
;
let idProc = 'dbg':pid
let msg = 'Start debugging process ':pid
echonl msg
;
loop
let msg = 'Sending SIGUSR1 signal and wait 1 second'
echonl msg
let capt = ''
let ret = 0
let signal = 10
invoke system&sendSignal(pid, signal)
; now waiting for shm to init from signaled process
let delay = 1
invoke system&sleep(delay)
;
let msg = '%':@prog
do WriteProcess(idProc, msg, ret)
breakon ret = OK
; retry ?
let msg = 'Process ':pid:" don't respond to debug start message (":msg:"), try again (Y/N) ? "
echo msg
input again
breakon again # 'y' and again # 'Y'
endloop
returnon ret # OK
;
; ok, we can debug background process now
; 1. read prompt
; 2. get command from user
; 3. send command
; 4. repeat from step 1
let msg = "Ready for debuging... ('q' to end session)"
echonl msg
let delay = 0.1
let debugging = @true
loop
do ReadProcess(msg, ret)
breakon ret # OK or msg = '%'
if msg # '' then
echo msg
loop
let cmd = ''
input cmd
breakon cmd # ''
endloop
;
do WriteProcess(idProc, cmd, ret)
breakon ret # OK
else
invoke system&sleep(delay)
endif
endloop
let msg = "End of debugging"
echonl msg
;
except
if debugging then
let cmd = '%'
do WriteProcess(idProc, cmd, ret)
endif
let msg = 'Exception ':@except
echonl msg
end
+366 -483
View File
File diff suppressed because it is too large. Load diff
+97 -86
View File
@@ -23,28 +23,33 @@
#ifndef DYNAMIC_H
#define DYNAMIC_H
#define cFM '\xFE' /* 254 */
#define cFM '\xFE' /* 254 */
#define cVM '\xFD' /* 253 */
#define cSVM '\xFC' /* 252 */
#define cTM '\xFB' /* 251 */
#define cSVM '\xFC' /* 252 */
#define cTM '\xFB' /* 251 */
#define sFM "\xFE"
#define sVM "\xFD"
#define sSVM "\xFC"
#define sTM "\xFB"
#define DYN_OK 0 // attention, DYN_OK doit etre egal a 0 sinon des tests seront KO...
#define DYN_ERR -1
enum {
DYN_OK = 0, // attention, DYN_OK doit etre egal a 0 sinon des tests seront KO...
DYN_ERR = -1,
#define DYN_FALSE 0
#define DYN_TRUE -1
DYN_FALSE = 0,
DYN_TRUE = -1,
#define DYN_LGNONE -1 // quand un parametre ne doit pas etre pris en compte, de type "lgChaine"
#define DYN_NONE 0 // quand un parametre ne doit pas etre pris en compte, de type "numChamp/numSousChamp separateurChamp/SousChamp"
DYN_LGNONE = -1, // quand un parametre ne doit pas etre pris en compte, de type "lgChaine"
DYN_NONE = 0, // quand un parametre ne doit pas etre pris en compte, de type "numChamp/numSousChamp separateurChamp/SousChamp"
#define DYN_ALL 0 // toues les occurences (dynChange...)
DYN_ALL = 0, // toues les occurences (dynChange...)
#define DYN_SORT_ASC 1
#define DYN_SORT_DESC 2
DYN_SORT_ASC = 1,
DYN_SORT_DESC = 2,
DYN_NOTFOUND = -1, // quand index ne trouve pas
DYN_NOTLOCATED = 0 // locate ne trouve pas
};
/*typedef struct
{
@@ -65,83 +70,89 @@ typedef var Dynamic;
si erreur de codage/lecture utf8, la norme est de le remplacer par le point de code \uFFFD (EF BF BD) et de continuer (à convertir en 3F ? par exemple en mono byte)
*/
#include "apidecl.h"
/* ********************************************** */
void NumberToSz(env * e, ent64s valeur, char * resultat, long * lg);
char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
char * Int32ToSz(ent32s valeur, long signe, long leftPad);
long dynInit(env * e, Dynamic * this, long lgmax);
long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
void dynFree(env * e, Dynamic * this);
void dynSetLen(env * e, Dynamic * this, long lg);
WAPIDECL char * NumberToSz(env * e, ent64s valeur, char * resultat, ent64s * lg);
WAPIDECL char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
WAPIDECL char * Int32ToSz(ent32s valeur, long signe, long leftPad);
WAPIDECL long dynInit(env * e, Dynamic * this, long lgmax);
WAPIDECL long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
WAPIDECL void dynFree(env * e, Dynamic * this);
WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg);
//long dynCarU8(env * e, Dynamic * this, long * pos);
//long dynLgU8(env * e, Dynamic * this);
long dynLengthUtf8(const char * p, long lg, int separator);
long dynNextUtf8(char ** p, long lg, long * pos, char * carU8, int separator);
long dynCtrl(env * e, Dynamic * this, long lg, long copier);
long Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
long UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
long dynSetAsSz(env * e, Dynamic * this, char * chaine);
long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
long dynRead(env * e, Dynamic * this, char * fichier);
long dynWrite(env * e, Dynamic * this, char * fichier);
ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
ent64s dynToNumber(env * e, Dynamic * this);
long dynConvertError(env * e, Dynamic * this);
long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
void dynBegin(env * e, Dynamic * this);
long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynCountUtf8(env * e, Dynamic * this, char * caractere4, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSetSubstrUtf8(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSubstrUtf8(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
long dynConvert(env * e, Dynamic * this, char * from, char * to);
void dynReplace(env * e, Dynamic * this, char from, char to);
long dynConvertUtf8(env * e, Dynamic * this, char * from, char * to);
void dynErase(env * e, Dynamic * this, char * car);
void dynEraseUtf8(env * e, Dynamic * this, char * car);
long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
long dynIndexSzUtf8(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
long dynConvertHexaToLong(Dynamic * valeur);
long dynConvertCharHexaToChar(char c1, char c2, char * c);
long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg);
long dynFmtUtf8(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char * filler, long lg);
long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadrage, char filler, long lg);
long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option);
long dynTrimUtf8(env * e, Dynamic * this, Dynamic * resultat, char * car, long option);
WAPIDECL long dynLengthUtf8(const char * p, long lg, int separator);
WAPIDECL long dynNextUtf8(char ** p, long lg, long * pos, char * carU8, int separator);
WAPIDECL long dynCtrl(env * e, Dynamic * this, long lg, long copier);
WAPIDECL long dynResize(env * e, Dynamic * this, long lgmax);
WAPIDECL long Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL long UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
WAPIDECL void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
WAPIDECL long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
WAPIDECL long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
WAPIDECL long dynSetAsSz(env * e, Dynamic * this, char * chaine);
WAPIDECL long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
WAPIDECL long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
WAPIDECL long dynRead(env * e, Dynamic * this, char * fichier);
WAPIDECL long dynWrite(env * e, Dynamic * this, char * fichier);
WAPIDECL ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
WAPIDECL ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
WAPIDECL ent64s dynToNumber(env * e, Dynamic * this);
WAPIDECL long dynConvertError(env * e, Dynamic * this);
WAPIDECL long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
WAPIDECL long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
WAPIDECL long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
WAPIDECL long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
WAPIDECL ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
WAPIDECL long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
WAPIDECL ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
WAPIDECL ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
WAPIDECL long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
WAPIDECL long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
WAPIDECL long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
WAPIDECL void dynBegin(env * e, Dynamic * this);
WAPIDECL long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
WAPIDECL long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
WAPIDECL long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynCountUtf8(env * e, Dynamic * this, char * caractere4, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSetSubstrUtf8(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSubstrUtf8(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
WAPIDECL long dynConvert(env * e, Dynamic * this, char * from, char * to);
WAPIDECL void dynReplace(env * e, Dynamic * this, char from, char to);
WAPIDECL long dynConvertUtf8(env * e, Dynamic * this, char * from, char * to);
WAPIDECL void dynErase(env * e, Dynamic * this, char * car);
WAPIDECL void dynEraseUtf8(env * e, Dynamic * this, char * car);
WAPIDECL long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
WAPIDECL long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
WAPIDECL long dynIndexSzUtf8(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
WAPIDECL long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg);
WAPIDECL long dynFmtUtf8(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char * filler, long lg);
WAPIDECL long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadrage, char filler, long lg);
WAPIDECL void dynTrimSpace(env * e, Dynamic * this);
WAPIDECL long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option);
WAPIDECL long dynTrimUtf8(env * e, Dynamic * this, Dynamic * resultat, char * car, long option);
WAPIDECL void dynCut(env * e, Dynamic * this, long pos);
WAPIDECL long dynCleanString(env * e, Dynamic * this, octet debut, octet fin, long convHexa);
WAPIDECL char * dynConvertCharToCharHexa(octet c);
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c);
WAPIDECL void dynCleanHexaMark(env * e, Dynamic * this);
WAPIDECL long dynEscapeHexaMark(env * e, Dynamic * this);
/* ********************************************** */
#endif
+140
View File
@@ -0,0 +1,140 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
// --- gestion protocole fastcgi
typedef struct {
long keepAlive;
long resteALireEntete;
long resteALireCorps;
char typeMessage; // BEGIN_REQUEST, etc.
long id; // id demande = id fastcgi
long lgCorps; // longueur corps du message (sans le padding)
long type; // type requete : OK ou ABORT
Dynamic param, dataIn, dataOut;
long error;
} modCtxFcgi;
enum {
FCGI_BEGIN_REQUEST = 1,
FCGI_ABORT_REQUEST = 2,
FCGI_END_REQUEST = 3,
FCGI_PARAMS = 4,
FCGI_STDIN = 5,
FCGI_STDOUT = 6,
/* role demande dans le BEGIN REQUEST */
FCGI_RESPONDER = 1,
FCGI_AUTHORIZER = 2,
FCGI_FILTER = 3,
/* code du "protocol status" lors du END REQUEST */
FCGI_REQUEST_COMPLETE = 0,
FCGI_CANT_MPX_CONN = 1,
FCGI_OVERLOADED = 2,
FCGI_UNKNOWN_ROLE = 3,
/* type requete en cours */
FCGI_REQUEST_OK = 0,
FCGI_REQUEST_ABORT = 1,
/* version prise en charge */
FCGI_VERSION = 1,
/* codes d'erreur */
FCGI_VERSION_UNSUPPORTED = 1,
FGCI_MESSAGETYPE_UNSUPPORTED = 2,
FGCI_PARAMETER_INCORRECT = 3,
/* codes retour */
FCGI_REQUEST_ERROR = -1,
FCGI_REQUEST_INPROGRESS = 0,
FCGI_REQUEST_AVAILABLE = 1
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WAPIDECL void Init(env * e, modCtxFcgi * ctx);
WAPIDECL void End(env * e, modCtxFcgi * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxFcgi * ctx, Dynamic * data);
WAPIDECL long MakeResponse(env * e, modCtxFcgi * ctx, long cr, Dynamic * reponse);
/*
exemples :
1. A simple request with no data on stdin, and a successful response:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2. Similar to example 1, but this time with data on stdin. The Web server chooses to send the parameters using more FCGI_PARAMS records than before:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3. Similar to example 1, but this time the application detects an error. The application logs a message to stderr, returns a page to the client, and returns non-zero exit status to the Web server. The application chooses to send the page using more FCGI_STDOUT records:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4. Two instances of example 1, multiplexed onto a single connection. The first request is more difficult than the second, so the application finishes the requests out of order:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
*/
+105 -328
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -20,359 +20,136 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
/* types de requete FCGI */
#define FCGI_BEGIN_REQUEST 1
#define FCGI_ABORT_REQUEST 2
#define FCGI_END_REQUEST 3
#define FCGI_PARAMS 4
#define FCGI_STDIN 5
#define FCGI_STDOUT 6
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
/* demande dans le BEGIN REQUEST */
#define FCGI_RESPONDER 1
#define FCGI_AUTHORIZER 2
#define FCGI_FILTER 3
#include "langage.h"
#include "dynamic.h"
/* code du "protocl status" lors du END REQUEST */
#define FCGI_REQUEST_COMPLETE 0
#define FCGI_CANT_MPX_CONN 1
#define FCGI_OVERLOADED 2
#define FCGI_UNKNOWN_ROLE 3
#include "fcgi.h"
/* codes d'erreurs du module */
#define WFC_OK 0 /* continuer a lire */
#define WFC_ERR 1
#define WFC_KEEPALIVE 2
#define WFC_REPONDRE 3
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modCtxFcgi ctxFcgi;
} modEtat;
/* Descritpion du message en cours ; id = 0 si aucun en cours */
struct {
octet vers;
ent16 id;
octet keepAlive;
octet req; /* requete en cours : entete lue, attente message */
ent16 lg; /* longueur message apres entete a lire */
Dynamic param;
Dynamic dataIn;
Dynamic dataOut;
} fcgiReq;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
/* enchainement des appels a faire
- lecture : lire la socket et appeler readFcgi
si retour = ERR, sortir en erreur
si retour = OK, continuer a lire (mettre a la fin du message en cours) et appeler readFcgi
si retour = REPONDRE, envoyer la reponse
- calculer la reponse, lire les donnes avec getFcgiDataIn
- ecriture : appel writeFcgi pour formater la sortie et lire le resultat avec getFcgiDataOut
si retour = ERR, sortir en erreur
ecrire tout le message dans la socket, quand ok :
appel writeFcgi pour formater la suite (blocs de 65535 octets max) etc. Quand fini :
appel writeEndFcgi pour formater le message de fin et lire le resultat avec getFcgiDataOut
ecrire le message de fin sur la socket
si retour = OK, fermer la socket
si retour = KEEPALIVE, garder la socket ouverte pour la suite
- si sortie en erreur ou erreur socket, fermer la socket
*/
long getFcgiDataIn(env * e, Dynamic * msg)
static int setError(modEtat * p, int err)
{
if(fcgiReq.vers != 0 && fcgiReq.id != 0)
{
/* copie de param + dataIn dans msg : msg<1,x> = nom param, msg<2,x> = valeur param, msg<3> contenu requete */
dynSetLen(e, msg, 0);
dynConcat(e, msg, &fcgiReq.param);
dynStoreSz(e, msg, 3, "", 0);
dynConcat(e, msg, &fcgiReq.dataIn);
return WFC_OK;
}
else
return WFC_ERR; /* TODO pas de requete en cours */
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
long getFcgiDataOut(env * e, Dynamic * msg)
{
if(fcgiReq.vers != 0 && fcgiReq.id != 0)
{
/* copie de dataOut dans msg */
dynSetLen(e, msg, 0);
dynConcat(e, msg, &fcgiReq.dataOut);
return WFC_OK;
}
else
return WFC_ERR; /* TODO pas de requete en cours */
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long readFcgi(env * e, Dynamic * msg)
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* "decodage" du message fcgi en entree */
if(msg->mLg < 8)
return WFC_RR; /* TODO longueur message incorrecte */
if(msg->ptr[0] != 1)
return WFC_ERR; /* TODO version message incorrecte (version 1 supportee uniquement) */
/* */
/* selon le type de message, controles */
if(fcgiReq.id != 0 && fcgiReq.vers != 0 && fcgi.req != 0)
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
/* entete requete lue => prise en charge du message */
if(msg->mLg < fcgiReq->lg)
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
return WFC_OK; /* TODO message de la requete de longueur incorrecte : continuer a lire */
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
Init(e, &p_etat->ctxFcgi);
//
}
if(fcgiReq.req == FCGI_BEGIN_REQUEST)
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
End(e, &p_etat->ctxFcgi);
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(msg->ptr[0] == 0 && msg->ptr[1] == FCGI_RESPONDER)
{
/* ok, seul role pris en charge */
fcgiReq.keepAlive = msg->ptr[2];
fcgiReq.req = 0;
fcgiReq.lg = 0;
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
}
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
{
return WFC_ERR; /* TODO role non pris en charge */
}
}
if(fcgiReq.req == FCGI_PARAMS)
{
/* decoder le message pour maj fcgiReq.param <1,x> et <2,x> */
long pos = 0, lgnam, lgval, nb;
nb = dynDcount(e, &fcgiReq.param, 1, cFM, cVM);
for(; pos < fcgiReq->lg;)
{
if((lgnam = msg->ptr[pos]) > 127)
{
if(pos + 3 >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
lgnam = (lgnam & 127) << 24 + msg->ptr[pos + 1] << 16 + msg->ptr[pos + 2] << 8 + msg->ptr[pos + 3];
pos += 3;
}
if(++pos >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
if((lgval = msg->ptr[pos]) > 127)
{
if(pos + 3 >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
lgval = (lgval & 127) << 24 + msg->ptr[pos + 1] << 16 + msg->ptr[pos + 2] << 8 + msg->ptr[pos + 3];
pos += 3;
}
if(pos + lgnam + lgval >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
/* TODO copier name/valeur dans <param> ; utilise fcgiReq.dataOut comme var. temp */
dynCtrl(e, &fcgiReq.dataOut, lgnam + lgval + 2, FALSE);
nb++;
pos++;
memcopie(fcgiReq.dataOut.ptr, msg->ptr + pos, lgnam);
dynSetLen(e, &fcgiReq.dataOut, lgnam);
dynStore(e, &fcgiReq.dataOut, 1, nb, fcgiReq.dataOut, cFM, cVM);
pos += lgnam
memcopie(fcgiReq.dataOut.ptr, msg->ptr + pos, lgval);
dynSetLen(e, &fcgiReq.dataOut, lgval);
dynStore(e, &fcgiReq.dataOut, 2, nb, fcgiReq.dataOut, cFM, cVM);
pos += lgval;
}
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return OK;
}
if(fcgiReq.req == FCGI_STDIN)
{
dynConcatSz(e, &fcgiReq.dataIn, msg->mPtr, fcgiReq.lg);
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
if(msg->ptr[1] == FCGI_BEGIN_REQUEST)
else if(modFnIs(e, "error", 5))
{
if(fcgiReq.id != 0 || fcgiReq.vers != 0)
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
return WFC_ERR; /* TODO une autre requete deja en cours ; envoyer une requete END REQUEST avec prot.status FCGI_CANT_MPX_CONN (1) ? return OKCANTMPX */
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
fcgiReq.vers = msg->ptr[0];
fcgiReq.id = msg->ptr[2] << 8 + msg->ptr[3];
fcgiReq.req = FCGI_BEGIN_REQUEST;
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
dynSetLen(e, &fcgiReq.param, 0);
dynSetLen(e, &fcgiReq.dataIn, 0);
dynSetLen(e, &fcgiReq.dataOut, 0);
return WFC_OK;
}
else if(msg->ptr[1] == FCGI_PARAMS)
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
return WFC_ERR; /* TODO pas de requete en cours */
long cr = ExtractMessage(e, &p_etat->ctxFcgi, param1);
param2->num = cr * NUM_FACTEUR;
if(cr == FCGI_REQUEST_AVAILABLE)
dynSetAs(e, param3, &p_etat->ctxFcgi.dataIn);
}
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
if(fcgiReq.lg > 0)
fcgiReq.req = FCGI_PARAMS;
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
return WFC_OK;
}
else if(msg->ptr[1] == FCGI_STDIN)
{
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
{
return WFC_ERR; /* TODO pas de requete en cours */
}
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
if(fcgiReq.lg > 0)
fcgiReq.req = FCGI_STDIN;
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
return (fcgiReq.lg == 0 ? WFC_REPONDRE : WFC_OK); /* requete STDIN vide = fin de la demande : reponse a faire */
}
/* ----------------------------------------------------------------------------------------------- */
else
{
return WFC_ERR; /* TODO type requete non prise en charge */
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
long writeFcgi(env * e, Dynamic * msg)
{
/* codage du message fcgi pour envoi : se trouvera dans "fcgi.dataOut" */
if(fcgiReq.vers != 0 && fcgiReq.id != 0 && fcgiReq.req == 0 && fcgiReq.lg == 0) ; else
{
return WFC_ERR; /* etat de la requete ne permet pas d'envoyer */
}
/* envoyer par bloc de 65535 cars max, en multiple de 8 */
if(msg->mLg > 65535)
fcgiReq.lg = 65535;
else
fcgiReq.lg = msg->mLg;
dynCtrl(e, &fcgiReq.dataOut, fcgiReq.lg + 16, FALSE); /* TODO test si ok ; 16 pour s'eviter des calculs ici... */
fcgiReq.dataOut.ptr[0] = fcgiReq.vers;
fcgiReq.dataOut.ptr[1] = FCGI_STDOUT;
fcgiReq.dataOut.ptr[2] = fcgiReq.id >> 8;
fcgiReq.dataOut.ptr[3] = fcgiReq.id & 255;
fcgiReq.dataOut.ptr[4] = fcgiReq.lg >> 8;
fcgiReq.dataOut.ptr[5] = fcgiReq.lg & 255;
fcgiReq.dataOut.ptr[6] = (8 - (fcgiReq.lg % 8)) & 7;
fcgiReq.dataOut.ptr[7] = 0;
/* */
memcopie(fcgiReq.dataOut.mPtr + 8, msg->mPtr, fcgiReq.lg);
fcgiReq.dataOut.mLg = fcgireq.lg + 8 + fcgiReq.dataOut.ptr[6];
/* a supprimer du debut de msg */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
}
long writeEndFcgi(env * e)
{
/* codage du message fcgi pour envoi : se trouvera dans "fcgi.dataOut" */
if(fcgiReq.vers != 0 && fcgiReq.id != 0 && fcgiReq.req == 0 && fcgiReq.lg == 0) ; else
{
return WFC_ERR; /* etat de la requete ne permet pas d'envoyer */
}
/* */
fcgiReq.dataOut.ptr[0] = fcgiReq.vers;
fcgiReq.dataOut.ptr[1] = FCGI_END_REQUEST;
fcgiReq.dataOut.ptr[2] = fcgiReq.id >> 8;
fcgiReq.dataOut.ptr[3] = fcgiReq.id & 255;
fcgiReq.dataOut.ptr[4] = 0;
fcgiReq.dataOut.ptr[5] = 8;
fcgiReq.dataOut.ptr[6] = 0; /* padding multiple de 8 */
fcgiReq.dataOut.ptr[7] = 0;
/* */
fcgiReq.dataOut.ptr[8] = 0; /* statut applicatif */
fcgiReq.dataOut.ptr[9] = 0;
fcgiReq.dataOut.ptr[10] = 0;
fcgiReq.dataOut.ptr[11] = 0;
fcgiReq.dataOut.ptr[12] = 0; /* protocole status, 0 = OK, 1 = FCGI_CANT_MPX_CONN */
fcgiReq.dataOut.ptr[13] = 0;
fcgiReq.dataOut.ptr[14] = 0;
fcgiReq.dataOut.ptr[15] = 0;
/* */
fcgiReq.dataOut.mLg = 16;
return (fcgiReq.keepAlive ? WFC_KEEPALIVE : WFC_OK);
}
long writeCantMpxFcgi(env * e, octet vers, ent16 id)
{
/* */
fcgiReq.dataOut.ptr[0] = vers;
fcgiReq.dataOut.ptr[1] = FCGI_END_REQUEST;
fcgiReq.dataOut.ptr[2] = id >> 8;
fcgiReq.dataOut.ptr[3] = id & 255;
fcgiReq.dataOut.ptr[4] = 0;
fcgiReq.dataOut.ptr[5] = 8;
fcgiReq.dataOut.ptr[6] = 0; /* padding multiple de 8 */
fcgiReq.dataOut.ptr[7] = 0;
/* */
fcgiReq.dataOut.ptr[8] = 0; /* statut applicatif */
fcgiReq.dataOut.ptr[9] = 0;
fcgiReq.dataOut.ptr[10] = 0;
fcgiReq.dataOut.ptr[11] = 0;
fcgiReq.dataOut.ptr[12] = 1; /* protocole status, 0 = OK, 1 = FCGI_CANT_MPX_CONN */
fcgiReq.dataOut.ptr[13] = 0;
fcgiReq.dataOut.ptr[14] = 0;
fcgiReq.dataOut.ptr[15] = 0;
/* */
fcgiReq.dataOut.mLg = 16;
return WFC_OK;
}
/* pour appel depuis un serveur http ("client" genere des requetes pour l'application fastcgi)
ou gestion de l'application fastcgi (type module php) "serveur" avec requetes entrantes (accept)
et multiplexage ou non des requetes (sur ID ; autorisation ou non)
recupere un socket existant (comme sslMod)
*
* exemple de flux
* FCGI_BEGIN_REQUEST, 1,1, FCGI_RESPONDER/1, 0 ou 1 CGI_KEEP_CONN ("keep alive")
* FCGI_PARAMS, 1,4, "\0xB\0x2SERVER_PORT80\0xB\0xESERVER_ADDR199.170.183.42 ... "
* FCGI_PARAMS, 1,4, ""
* FCGI_STDIN, 1,5, "quantity=100&item=3047936"
* FCGI_STDIN, 1,5, "" ==> marque la fin de la question et attend de la reponse (au moins ce message apres BEGIN REQUEST)
*
* FCGI_STDOUT, 1,6, "Content-type: text/html\r\n\r\n<html>\n<head> ... "
* FCGI_STDOUT, 1,6, ""
* FCGI_END_REQUEST, 1,3, 0, FCGI_REQUEST_COMPLETE/0
*
* FastCGI
*---------
* chaque requete : entete 8 octets + contenu (multiple de 8)
* vers | type | MSB id LSB | MSB lg LSB |padlg | reser| requete
* +------+------+------+------+------+------+------+------+-----......------+
* 1 lg+padlg = multiple de 8
* type
* 1:BEGIN 3:END 4:PARAMS (paires Name/Value) 5:STDIN (brut) 6:STDOUT (brut)
*
* contenu requete pour chaque type
* 1: MSB role LSB |flags | reserve
* +------+------+------+------+------+------+------+------+ lg = 8
* role -> responder = 1 ; flags -> 0/1 : keep connection alive
* si keep alive = 1 avec fork, a la fin de la reponse, garder la socket ouverte
*
* 3: MSB . . status . . . LSB |pro st| reserve
* +------+------+------+------+------+------+------+------+ lg = 8
* pro st -> protocol status -> complete = 0
* status = statut applicatif (?)
*
* 4: lg nam|lg val| name | value |
* +------+------+--.....----+--...----+
* avec lg name et lg value < 127
* si > 127, encodage sur 4 octets MSB x x LSB ; lg maxi = 2^31-1 (bit 31 non significatif = 1)
*
* 5/6: contenu "libre"
*
*/
+388
View File
@@ -0,0 +1,388 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "fcgi.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
static long LireParametre(env * e, modCtxFcgi * ctx)
{
long pos = 0, len = ctx->dataOut.mLg;
octet * ptr = (octet *)ctx->dataOut.mPtr;
while(pos < len)
{
octet lgNom, lgVal;
long lgNomLong, lgValLong;
lgNom = ptr[pos++];
if(lgNom > 127)
{
if(pos + 3 > len)
return DYN_ERR; /* erreur */
lgNomLong = lgNom & 127;
lgNomLong = lgNomLong * 256 + ptr[pos++];
lgNomLong = lgNomLong * 256 + ptr[pos++];
lgNomLong = lgNomLong * 256 + ptr[pos++];
}
else
lgNomLong = lgNom;
//
if(pos >= len)
return DYN_ERR; /* erreur */
lgVal = ptr[pos++];
if(lgVal > 127)
{
if(pos + 3 > len)
return DYN_ERR; /* erreur */
lgValLong = lgVal & 127;
lgValLong = lgValLong * 256 + ptr[pos++];
lgValLong = lgValLong * 256 + ptr[pos++];
lgValLong = lgValLong * 256 + ptr[pos++];
}
else
lgValLong = lgVal;
//
if(pos + lgNomLong + lgValLong > len)
return DYN_ERR; /* erreur */
// lire les lgNomLong octets du nom du parametre et maj dans mParam<1,x>
// et lire les lgValLong octets de la valeur du parametre et maj dans mParam<2,x>
dynInsSz(e, &ctx->param, 1, 1, (char *)(ptr + pos), lgNomLong, cFM, cVM);
pos += lgNomLong;
dynInsSz(e, &ctx->param, 2, 1, (char *)(ptr + pos), lgValLong, cFM, cVM);
pos += lgValLong;
}
return OK;
}
static long EcrireEntete(env * e, modCtxFcgi * ctx, octet type, long id, long lg, long * lgpad)
{
if(dynCtrl(e, &ctx->dataOut, ctx->dataOut.mLg + 8, TRUE) != DYN_OK)
return DYN_ERR;
/* */
octet * ptr = (octet *)(ctx->dataOut.ptr + ctx->dataOut.mLg);
*lgpad = (8 - (lg % 8)) % 8;
dynSetLen(e, &ctx->dataOut, ctx->dataOut.mLg + 8);
/* */
*ptr++ = FCGI_VERSION;
*ptr++ = type;
*ptr++ = (id / 256) % 256; // MSB id
*ptr++ = id % 256; // LSB id
*ptr++ = (lg / 256) % 256; // MSB lg
*ptr++ = lg % 256; // LSB lg
*ptr++ = *lgpad;
*ptr = 0;
return OK;
}
static long EcrireCorps(env * e, modCtxFcgi * ctx, octet type, long crApplicatif, octet status)
{
switch(type)
{
case FCGI_END_REQUEST:
{
if(dynCtrl(e, &ctx->dataOut, ctx->dataOut.mLg + 8, TRUE) != DYN_OK)
return DYN_ERR;
//
octet * ptr = (octet *)(ctx->dataOut.ptr + ctx->dataOut.mLg);
dynSetLen(e, &ctx->dataOut, ctx->dataOut.mLg + 8);
//
*(ptr + 3) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 2) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 1) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 0) = crApplicatif % 256;
ptr += 4;
*ptr++ = status;
*ptr++ = 0;
*ptr++ = 0;
*ptr++ = 0;
break;
}
}
return OK;
}
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxFcgi * ctx)
{
ctx->keepAlive = 0;
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->typeMessage = 0; // BEGIN_REQUEST, etc.
ctx->id = 0; // id demande = id fastcgi
ctx->lgCorps = 0; // longueur corps du message
ctx->type = 0;
ctx->error = 0;
/* */
dynInit(e, &ctx->param, DYN_LGMIN);
dynInit(e, &ctx->dataIn, DYN_LGMIN);
dynInit(e, &ctx->dataOut, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxFcgi * ctx)
{
dynFree(e, &ctx->param);
dynFree(e, &ctx->dataIn);
dynFree(e, &ctx->dataOut);
}
WAPIDECL long ExtractMessage(env * e, modCtxFcgi * ctx, Dynamic * data)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
while(data->mLg > 0)
{
if(ctx->resteALireEntete == -1)
{
// entete fcgi attendue
if(data->mLg < 8)
return FCGI_REQUEST_INPROGRESS; /* attndre les donnees suivantes */
octet * ptr = (octet *)data->ptr;
octet vers = *ptr++;
ctx->typeMessage = *ptr++;
ctx->id = (*ptr++) * 256;
ctx->id += *ptr++;
long lg = (*ptr++) * 256;
lg += *ptr++;
long lgpad = *ptr;
dynCut(e, data, 8);
if(vers != FCGI_VERSION)
{
ctx->error = FCGI_VERSION_UNSUPPORTED;
return FCGI_REQUEST_ERROR; // erreur : version non prise en charge
}
//
ctx->resteALireEntete = 0;
ctx->lgCorps = lg;
ctx->resteALireCorps = lg + lgpad;
//
if(ctx->typeMessage == FCGI_BEGIN_REQUEST)
{
dynSetLen(e, &ctx->dataIn, 0);
dynSetLen(e, &ctx->param, 0);
}
if(ctx->typeMessage == FCGI_STDIN && ctx->resteALireCorps == 0)
{
// toutes les données de la requete ont ete recues : traiter puis envoyer reponse
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->type = FCGI_REQUEST_OK;
return FCGI_REQUEST_AVAILABLE;
}
if(ctx->typeMessage == FCGI_ABORT_REQUEST)
{
// forcer une reponse END_REQUEST
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->type = FCGI_REQUEST_ABORT;
return FCGI_REQUEST_AVAILABLE;
}
if(ctx->resteALireCorps == 0)
{
// message vide : attendre de nouveau l'entete
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
}
continue;
}
if(ctx->resteALireCorps > 0)
{
if(data->mLg < ctx->resteALireCorps)
return FCGI_REQUEST_INPROGRESS; // attendre : tout n'est pas recu
//
dynLet(e, &ctx->dataOut, data->mPtr, ctx->lgCorps); // ne pas prendre le padding...
dynCut(e, data, ctx->resteALireCorps);
ctx->resteALireCorps = 0;
ctx->resteALireEntete = -1;
//
switch(ctx->typeMessage)
{
case FCGI_BEGIN_REQUEST:
// verifier role = FCGI_RESPONDER ? si oui et erreur, forcer une reponse ABORT
ctx->keepAlive = (ctx->dataOut.mPtr[2] == 1);
// nota : durant les tests avec nginx, cela ne fonctionne pas : nginx ne reutilise pas la derniere socket ! Flag a remettre lors du EndRequest ?
break;
case FCGI_STDIN:
dynConcat(e, &ctx->dataIn, &ctx->dataOut);
break;
case FCGI_PARAMS:
// maj param sur attributs 1 & 2 en multi-valeurs (lu de dataOut)
if(LireParametre(e, ctx) != OK)
{
ctx->error = FGCI_PARAMETER_INCORRECT;
return FCGI_REQUEST_ERROR;
}
break;
default:
ctx->error = FGCI_MESSAGETYPE_UNSUPPORTED;
return FCGI_REQUEST_ERROR;
break;
}
}
}
return FCGI_REQUEST_INPROGRESS;
}
WAPIDECL long MakeResponse(env * e, modCtxFcgi * ctx, long cr, Dynamic * reponse)
{
long lgReponse = reponse->mLg, lgpad;
long debut = 0;
dynSetLen(e, &ctx->dataOut, 0);
/* */
if(ctx->type == FCGI_REQUEST_OK)
{
while (lgReponse > 0)
{
long lg;
if(lgReponse > 65535)
lg = 65535;
else
lg = lgReponse;
//
if(EcrireEntete(e, ctx, FCGI_STDOUT, ctx->id, lg, &lgpad) != OK)
return DYN_ERR;
dynConcatSz(e, &ctx->dataOut, reponse->mPtr + debut, lg);
if(lgpad > 0)
{
char pad[8] = "0000000";
pad[(lgpad) % 8] = 0;
dynConcatSz(e, &ctx->dataOut, pad, DYN_LGNONE);
}
//
lgReponse -= lg;
debut += lg;
}
// envoyer STDOUT de longueur nulle
if(EcrireEntete(e, ctx, FCGI_STDOUT, ctx->id, 0, &lgpad) != OK) // a envoyer si ABORT_REQUEST demande par le serveur Web ?
return DYN_ERR;
} // sinon forcement ABRT = que le END_REQUEST
// envoyer END_REQUEST
if(EcrireEntete(e, ctx, FCGI_END_REQUEST, ctx->id, 8, &lgpad) != OK)
return DYN_ERR;
if(EcrireCorps(e, ctx, FCGI_END_REQUEST, cr, FCGI_REQUEST_COMPLETE) != OK)
return DYN_ERR;
//
// reponse mis a jour au format fcgi
dynSetAs(e, reponse, &ctx->dataOut);
return OK;
}
/*
exemples :
1. A simple request with no data on stdin, and a successful response:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2. Similar to example 1, but this time with data on stdin. The Web server chooses to send the parameters using more FCGI_PARAMS records than before:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3. Similar to example 1, but this time the application detects an error. The application logs a message to stderr, returns a page to the client, and returns non-zero exit status to the Web server. The application chooses to send the page using more FCGI_STDOUT records:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4. Two instances of example 1, multiplexed onto a single connection. The first request is more difficult than the second, so the application finishes the requests out of order:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
---------
FastCGI
---------
chaque requete : entete 8 octets + contenu (multiple de 8)
vers | type | MSB id LSB | MSB lg LSB |padlg | reser| requete
+------+------+------+------+------+------+------+------+-----......------+
1 lg+padlg = multiple de 8
type
1:BEGIN 3:END 4:PARAMS (paires Name/Value) 5:STDIN (brut) 6:STDOUT (brut)
contenu requete pour chaque type
1: MSB role LSB |flags | reserve
+------+------+------+------+------+------+------+------+ lg = 8
role -> responder = 1 ; flags -> 0/1 : keep connection alive
si keep alive = 1 avec fork, a la fin de la reponse, garder la socket ouverte
3: MSB . . status . . . LSB |pro st| reserve
+------+------+------+------+------+------+------+------+ lg = 8
pro st -> protocol status -> complete = 0
status = statut applicatif (?)
4: lg nam|lg val| name | value |
+------+------+--.....----+--...----+
avec lg name et lg value < 127
si > 127, encodage sur 4 octets MSB x x LSB ; lg maxi = 2^31-1 (bit 31 non significatif = 1)
5/6: contenu "libre"
*/
+224 -129
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -25,225 +25,317 @@
#include <time.h>
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#else
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#else
#include "windows.h" // pour les fonctions FindFile...
#endif
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_RENAME = 1,
EXMOD_REMOVE = 2,
EXMOD_READ = 3,
EXMOD_WRITE = 4,
EXMOD_ACCESS = 5, /* open seek */
EXMOD_NB = 5
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Rename error",
"Delete error",
"Read error",
"Write error",
"Access error while opening/seeking" // 5
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// les differentes fonctions : file.create/open/close/read/write/get/set/size/dir
// ( init/end/vers/error sont obligatoires pour tout module )
// create : creer un fichier ; flag overwrite = false : exception si existe, si flag = true, raz du fichier existant TODO
// open : ouvre un fichier existant, exception si inexistant TODO
// close : fermeture du fichier TODO
// read : lecture du fichier TODO
// write : ecriture du fichier TODO
// - - - - - - - - - - - - - - - - - - - -
// get : recupere dans param un dynamic contenant le fichier
// set : ecrit depuis param le dynamic dans le fichier (param = nom FM contenu)
// size : donne la taille sur disque du fichier
// dir : donne la liste des fichiers et repertoires d'un repertoire
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(p_etat == NULL)
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
exc = EX_MODETAT;
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "create", 6) == 0)
else if(modFnIs(e, "rename", 6))
{
// todo...
// test
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
p_etat->error++;
printf("mod create %d\n", p_etat->error);
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "get", 3) == 0)
{
/* utilisation de dynRead qui fait le travail, param1 : nom, param2 : contenu lu */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramOldPath = getParam(e, "oldPath", 7);
var * paramNewPath = getParam(e, "newPath", 7);
if(paramOldPath == NULL || paramNewPath == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramOldPath->type != VAR_DYNAMIC || paramNewPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynRead(e, param2, param1->mPtr) != DYN_OK)
exc = setError(p_etat, 1);
if(rename(paramOldPath->mPtr, paramNewPath->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "delete", 6))
{
/* copie du code de dynWrite, avec modif param1 : nom, param2 : contenu a ecrire */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
if(paramPath == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(remove(paramPath->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "append", 6))
{
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramContent = getParam(e, "content", 7);
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
else if(paramPath->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FILE * fic;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
if((fic = fopen(paramPath->mPtr, "ab")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "w")) == NULL)
if((fic = fopen(paramPath->mPtr, "a")) == NULL) /* mode "a" creer le fichier s'il n'existe pas (Unix et Windows) */
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
exc = setError(p_etat, EXMOD_ACCESS);
else
{
if(fwrite(param2->mPtr, param2->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
if(fseek(fic, 0, SEEK_END) != 0)
exc = setError(p_etat, EXMOD_ACCESS);
else if(fwrite(paramContent->mPtr, paramContent->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, EXMOD_WRITE);
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "size", 4) == 0)
else if(modFnIs(e, "get", 3))
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
/* */
if(param1 == NULL || param2 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramContent = getParam(e, "content", 7);
/* utilisation de dynRead qui fait le travail */
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramContent->type != VAR_DYNAMIC)
var_let(e, paramContent, &e->int_dynamic, FALSE, FALSE);
if(dynRead(e, paramContent, paramPath->mPtr) != DYN_OK)
exc = setError(p_etat, EXMOD_READ);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramContent = getParam(e, "content", 7);
/* copie du code de dynWrite, avec modif param1 : nom, param2 : contenu a ecrire */
if(paramPath == NULL || paramContent == NULL)
exc = EX_MODPARAM;
else if(paramPath->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FILE * fic;
#ifndef UNIX
if((fic = fopen(paramPath->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(paramPath->mPtr, "w")) == NULL)
#endif
exc = setError(p_etat, EXMOD_ACCESS); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fwrite(paramContent->mPtr, paramContent->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, EXMOD_WRITE); /* erreur generique : lire la vraie erreur ailleurs */
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "size", 4))
{
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramLength = getParam(e, "length", 6);
if(paramPath == NULL || paramLength == NULL)
exc = EX_MODPARAM;
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
if((fic = fopen(paramPath->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "r")) == NULL)
if((fic = fopen(paramPath->mPtr, "r")) == NULL)
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
exc = setError(p_etat, EXMOD_ACCESS); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fseek(fic, 0, SEEK_END) != 0)
exc = setError(p_etat, 1); /* vraie erreur a mettre */
exc = setError(p_etat, EXMOD_ACCESS); /* vraie erreur a mettre */
else
{
if(paramLength->type != VAR_NUMBER)
var_let(e, paramLength, &e->int_number, FALSE, FALSE);
lg = ftell(fic); /* longueur du fichier */
param2->num = lg * NUM_FACTEUR;
paramLength->num = lg * NUM_FACTEUR;
}
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "dir", 3) == 0)
else if(modFnIs(e, "dir", 3))
{
/* copie du code de dynRead, plus court */
if(param1 == NULL)
/* get param in the right order */
var * paramPath = getParam(e, "path", 4);
var * paramFileList = getParam(e, "fileList", 8);
if(paramPath == NULL || paramFileList == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC)
else if(paramPath->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramFileList->type != VAR_DYNAMIC)
var_let(e, paramFileList, &e->int_dynamic, FALSE, FALSE);
/* copie du code de dynRead, plus court */
#ifdef UNIX
DIR * rep = NULL;
if((rep = opendir(param1->mPtr)) == NULL)
exc = setError(p_etat, 1); /* todo vraie erreur */
if((rep = opendir(paramPath->mPtr)) == NULL)
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
else
{
dynSetLen(e, param1, 0); // idem raz
dynSetLen(e, paramFileList, 0);
struct dirent * fic = NULL;
while ((fic = readdir(rep)) != NULL)
{
if((fic->d_type == DT_DIR || fic->d_type == DT_REG) && strcmp(fic->d_name,".") != 0 && strcmp(fic->d_name,"..") != 0)
{
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, fic->d_name, DYN_LGNONE);
if(paramFileList->mLg > 0)
dynConcatSz(e, paramFileList, sFM, 1);
dynConcatSz(e, paramFileList, fic->d_name, DYN_LGNONE);
}
}
/* */
@@ -252,32 +344,35 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
#else
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
dynConcatSz(e, param1, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(param1->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
dynLet(e, paramFileList, paramPath->mPtr, paramPath->mLg);
dynConcatSz(e, paramFileList, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(paramFileList->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
{
dynSetLen(e, param1, 0); // idem raz
dynSetLen(e, paramFileList, 0);
for(int cr = -1;cr != 0;)
{
if(strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
{
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, FindFileData.cFileName, DYN_LGNONE);
if(paramFileList->mLg > 0)
dynConcatSz(e, paramFileList, sFM, 1);
dynConcatSz(e, paramFileList, FindFileData.cFileName, DYN_LGNONE);
}
cr = FindNextFile(hFind, &FindFileData);
}
FindClose(hFind);
}
else
exc = setError(p_etat, 1); /* todo vraie erreur */
{
dynSetLen(e, paramFileList, 0);
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+47 -38
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,46 +27,35 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
env e;
long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, 10);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, 10, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
/*
blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10
sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20
return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30
continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40
new,41,class,42,this,43,parent,44,free,45,precision,46,setsep,47,int,48,frac,49,abs,50
neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60
format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70
lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80
indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90
multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99
new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50
neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60
search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70
gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80
endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90
numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100
modsep,101,other,102
*/
struct {
ent16 blank,comment,begin,background,library,end,except,throw,catch,include;
ent16 sub,endsub,if_,then,else_,elseif,endif,do_,call,invoke;
ent16 return_,returnon,loop,endloop,foreach,in,like,endfor,break_,breakon;
ent16 continue_,continueon,nop,part,echonl,echo,input,declare,let,delet;
ent16 new,class,this,parent,free,precision,setsep,int_,frac,abs;
ent16 neg,round,type,len,count,dcount,field,index,search,change;
ent16 format,insert,remove,tonum,tostring,equal,diff,gt,lt,gte;
ent16 lte,and,or,not,beginpar,endpar,beginh,endh,begins,ends;
ent16 indirect,typeof_,stringdq,stringq,ident,varsys,numberdec,numberint,minus,plus;
ent16 multiply,divide,divident,modulo,concat,listesep,identsep,modsep,other;
ent16 new,class,this,parent,hold,precision,setsep,int_,frac,abs;
ent16 neg,round,sqrt,exp,type,len,count,dcount,field,index;
ent16 search,sortedsearch,change,format,insert,remove,tonum,tostring,equal,diff;
ent16 gt,lt,gte,lte,and,or,not,beginpar,endpar,beginh;
ent16 endh,begins,ends,indirect,typeof_,stringdq,stringq,ident,varsys,numberdec;
ent16 numberint,minus,plus,multiply,divide,divident,modulo,concat,listesep,identsep;
ent16 modsep,other;
} r;
void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
@@ -119,7 +108,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.class = rg(e, regles, "class", tmp);
r.this = rg(e, regles, "this", tmp);
r.parent = rg(e, regles, "parent", tmp);
r.free = rg(e, regles, "free", tmp);
r.hold = rg(e, regles, "hold", tmp);
r.precision = rg(e, regles, "precision", tmp);
r.setsep = rg(e, regles, "setsep", tmp);
r.int_ = rg(e, regles, "int", tmp);
@@ -128,15 +117,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 +136,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 +147,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 +158,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.ident = rg(e, regles, "ident", tmp);
r.varsys = rg(e, regles, "varsys", tmp);
r.numberdec = rg(e, regles, "numberdec", tmp);
/* */
r.numberint = rg(e, regles, "numberint", tmp);
r.minus = rg(e, regles, "minus", tmp);
r.plus = rg(e, regles, "plus", tmp);
/* */
r.multiply = rg(e, regles, "multiply", tmp);
r.divide = rg(e, regles, "divide", tmp);
r.divident = rg(e, regles, "divident", tmp);
@@ -177,21 +169,37 @@ 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);
}
enum {
TAB_COUNT = 3,
COMMENT_EOL = 8
};
static void formatage_asm(Dynamic * s, Dynamic * f)
{
// TODO
}
static void formatage(Dynamic * s, Dynamic * f, int type)
{
// s : source ; f : source apres formatage, type : 1 w, 2 pcode
if(type == 2)
{
formatage_asm(s, f);
return;
}
//Dynamic token; /* contient les tokens suite au decodage lex d'une ligne */
ent16 tok; //,tok2,tok3; /* token lu par la macro ci-dessous "nreg" */
long n; /* indice en cours dans les token (parametre de la macro "nreg") base 1 */
//#define nreg(x) ((x)*2 > token.mLg ? 0 : *(ent16 *)(token.mPtr + (x)*2 - 2))
#define ntok(x) dynExtractSubFieldAsNumber(&e, &valex, 2, x, &tmp)
//
#define TAB_COUNT 3
#define COMMENT_EOL 8
//#define TAB_COUNT 3
//#define COMMENT_EOL 8
//
Dynamic trav, tmp, lig; /* variables de travail */
Dynamic regles; /* regles lex */
@@ -236,7 +244,7 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
if(valex.mLg == 0)
continue; // ligne vide
//
// contenu champ "n" : dynField(e, valex, tmp, 1, n, cFM, cVM, 1); dynIconv(e, tmp, encours, "X"); // en hexa
// contenu champ "n" : dynField(e, valex, tmp, 1, n, cFM, cVM, 1); hex2str(e, tmp, encours); // en hexa
// position source du champ "n" : dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
long nbval = dynDcount(&e, &valex, cVM, 2, cFM);
// MAJ var token pour fonctionner avec la macro nreg()
@@ -314,7 +322,7 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
//if(tok2 != r.comment)
// pos_comment = -1;
}
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 10 (par exemple), >= position actuelle
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 8, >= position actuelle
// + formatage debut de ligne
if(pos_comment == -1)
{
@@ -326,7 +334,8 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
}
else
{
dynSubstr(&e, &trav, &lig, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
dynSubstr(&e, &trav, &tmp, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
dynTrim(&e, &tmp, &lig, ' ', 2);
#ifdef WINLIB
dynSubstr(&e, &trav, &tmp, pos_comment - 1, ((intptr_t)(trav.mPtr)) - pos_comment, 1, DYN_NONE, 10, DYN_NONE);
#else
+217
View File
@@ -0,0 +1,217 @@
begin gened
;
class Gened = {Base}
;
let Gened.trace = @false
;
let Gened.name = ''
let Gened.query = ''
;
let Gened.breakInfo = ''
let Gened.breakCount = 0
;
let Gened.recordCount = 0
let Gened.init = @true
let Gened.first = @true
let Gened.last = @false
let Gened.currentRecord = ''
let Gened.precRecord = ''
;
; breakInfo, champs en multi-valeurs :
let Gened.BREAKFIELDNUM = 1 ; {1} = num champ dans l'enregistrement
let Gened.BREAKFIELDVAL = 2 ; {2} = valeur champ enreg en cours
let Gened.BREAKFIELDVALPREC = 3 ; {2} = valeur champ enreg en cours
let Gened.BREAKDIFF = 4 ; {4} = flag si difference pour ce niveau
let Gened.BREAKCOUNTER = 5 ; {5} = compteur d'enregs pour ce niveau de rupture
;
sub Gened.ParamSection()
; maj de name/query/breakInfo{1}
if this.trace then
echonl "ED => in ParamSection"
endif
except
endsub
;
sub Gened.SetQuery()
; creer la requete de recuperation des enregistrements (utilise query)
if this.trace then
echonl "ED => in SetQuery"
endif
except
endsub
;
sub Gened.GetNextRecord()
; recupere l'enregistrement suivant, et l'ecrit dans this.currentRecord et this.last = @false, sinon this.last = @true et this.currentRecord = ''
if this.trace then
echonl "ED => in GetNextRecord"
endif
except
endsub
;
sub Gened.EndOfQuery()
; terminer la requete de recup. des enregistrements
if this.trace then
echonl "ED => in EndOfQuery"
endif
except
endsub
;
sub Gened.InitSection()
if this.trace then
echonl "ED => in InitSection"
endif
except
endsub
;
sub Gened.DoSection()
if this.trace then
echonl "ED => in DoSection, record #23":this.recordCount:' => ':this.currentRecord
endif
except
endsub
;
sub Gened.EndSection()
if this.trace then
echonl "ED => in EndSection"
endif
except
endsub
;
sub Gened.LevelBreakHeader(level)
if this.trace then
echonl "ED => in LevelBreakHeader:":level:' ':field(this.breakInfo{this.BREAKFIELDVAL, level}, "#FC", level)
endif
except
endsub
;
sub Gened.LevelBreakFooter(level)
if this.trace then
echonl "ED => in LevelBreakFooter:":level:' ':field(this.breakInfo{this.BREAKFIELDVALPREC, level}, "#FC", level):' last(':this.last:')'
endif
except
endsub
;
sub Gened.Execute()
declare un, moinsUn, breakVal, breakNum ; compteur des niveaux de rupture
let un = 1
let moinsUn = neg(1)
declare SVM
let SVM = "#FC"
let breakVal = ''
let breakNum = 0
;
do this.ParamSection()
;
do this.SetQuery()
;
do this.GetNextRecord()
;
let this.recordCount = 0
let this.breakCount = dcount(this.breakInfo, this.BREAKFIELDNUM)
;
do this.InitSection()
;
if not(this.last) then
loop
breakon this.last
if not(this.init) then
do this.GetNextRecord()
else
let this.init = @false
endif
;
foreach breakNum in un, this.breakCount
let breakVal = this.currentRecord{ this.breakInfo{this.BREAKFIELDNUM, breakNum} }
if breakNum > un then
let breakVal = this.breakInfo{this.BREAKFIELDVAL, breakNum - 1}:SVM:breakVal
endif
let this.breakInfo{this.BREAKFIELDVAL, breakNum} = breakVal
let this.breakInfo{this.BREAKDIFF, breakNum} = (this.breakInfo{this.BREAKFIELDVALPREC, breakNum} # breakVal)
endfor
;
if this.breakCount > 0 and (this.first or this.last or this.breakInfo{4, this.breakCount}) then
if not(this.first) then
foreach breakNum in this.breakCount, un, moinsUn
if this.last or this.breakInfo{this.BREAKDIFF, breakNum} then
do this.LevelBreakFooter(breakNum)
endif
endfor
endif
if not(this.last) then
foreach breakNum in un, this.breakCount
if this.first or this.breakInfo{this.BREAKDIFF, breakNum} then
let this.breakInfo{this.BREAKCOUNTER, breakNum} = 0
do this.LevelBreakHeader(breakNum)
endif
endfor
endif
let this.first = @false
endif
;
if not(this.last) then
foreach breakNum in un, this.breakCount
let this.breakInfo{this.BREAKCOUNTER, breakNum} = this.breakInfo{this.BREAKCOUNTER, breakNum} + 1
endfor
let this.recordCount = this.recordCount + 1
;
do this.DoSection()
;
let this.precRecord = this.currentRecord
let this.breakInfo{this.BREAKFIELDVALPREC} = this.breakInfo{this.BREAKFIELDVAL}
endif
endloop
endif
;
do this.EndSection()
;
do this.EndOfQuery()
;
except
; TODO
echonl "Exception in Execute"
endsub
;
class EdTest = {Gened}
;
sub EdTest.SetQuery()
declare path
let path = 'data.txt'
let this.data = ''
let this.line = 0
;
invoke file&get(path, this.data)
let this.data = change(this.data, '#0A', @fm)
;
let this.breakInfo = "3":@vm:5
;
do parent.SetQuery
except
endsub
;
sub EdTest.InitSection()
;echonl 'nb break: ':this.breakCount
do parent.InitSection
except
endsub
;
sub EdTest.GetNextRecord()
let this.line = this.line + 1
let this.currentRecord = this.data{this.line}
if this.currentRecord = '' then
let this.last = @true
else
let this.currentRecord = change(this.currentRecord, ';', @fm)
endif
;echonl "EdTest GetNextRecord: ":this.last:' / line ':this.line:' => ':this.currentRecord
except
endsub
;
declare ed
let ed = new EdTest
let ed.trace = @true
do ed.Execute()
;
except
;
echonl "Exception in main: ":@except
end
+22 -219
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,221 +27,18 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
env e;
long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, 10);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, 10, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
struct {
long blanc, nomregle, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} r;
void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
{
r.blanc = rg(e, regles, "blanc", tmp); // 1
r.nomregle = rg(e, regles, "nomregle", tmp); // 2
r.debut = rg(e, regles, "debut", tmp); // 3
r.fin = rg(e, regles, "fin", tmp); // 4
r.occ = rg(e, regles, "occ", tmp); // 5
r.infini = rg(e, regles, "infini", tmp); // 6
r.commentaire = rg(e, regles, "commentaire", tmp); // 7
r.intervalle = rg(e, regles, "intervalle", tmp); // 8
r.hexa = rg(e, regles, "hexa", tmp); // 9
r.car = rg(e, regles, "car", tmp); // 10
r.reste = rg(e, regles, "reste", tmp); // 11
}
long parse(Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours)
{
#define nreg(x) ((x)*2 > trav->mLg ? 0 : *(ent16 *)(trav->mPtr + (x)*2 - 2))
/* */
static int numlig = 0;
numlig++;
/* */
if(valex->mLg == 0)
return OK; /* ligne vide */
/* */
int nbres = dynDcount(&e, resultat, 10, DYN_NONE, DYN_NONE);
int nbval = dynDcount(&e, valex, cVM, 2, cFM);
ent16 regle;
dynSetLen(&e, trav, 0);
dynSetLen(&e, encours, 0);
for(int ival = nbval; ival > 0; ival--)
{
/* suppression des regles 1 et 7 (blanc et commentaire) */
dynField(&e, valex, tmp, 2, ival, cFM, cVM, 1);
regle = dynToNum(&e, tmp, DYN_FALSE, 0);
if(regle == r.blanc || regle == r.commentaire)
{
dynDel(&e, valex, 1, ival, cFM, cVM, 1);
dynDel(&e, valex, 2, ival, cFM, cVM, 1);
dynDel(&e, valex, 3, ival, cFM, cVM, 1);
}
else
{
if(dynCtrl(&e, trav, trav->mLg + 2, TRUE) != DYN_OK)
return DYN_ERR;
if(trav->mLg > 0)
memcopie(trav->mPtr + 2, trav->mPtr, trav->mLg);
*(ent16 *)(trav->mPtr) = regle;
dynSetLen(&e, trav, trav->mLg + 2);
}
}
//dynDel(&e, valex, 2, DYN_NONE, cFM, DYN_NONE, 1);
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
//for(int i=1;i<=trav->mLg/2;i++) printf("%d,",nreg(i)); printf("\n");
/* debut d'analyse des tokens : nomregle */
if(nreg(1) != r.nomregle)
{
dynField(&e, valex, tmp, 3, 1, cFM, cVM, 1);
printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* liste de et/ou */
for(ent16 n = 2;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == r.debut || regle == r.car) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : car ou debut et/ou attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* et */
if(n == 2)
dynStoreSz(&e, valex, 4, DYN_NONE, "", 0, cFM, DYN_NONE);
else
dynConcatSz(&e, valex, ";", 1);
/* */
if(regle == r.car)
{
/* 1 caractere = (1,1,car) (raccourci d'ecriture) */
dynConcatSz(&e, valex, "1,1,", 4);
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(&e, valex, tmp);
n++;
continue;
}
if(nreg(n+1) == r.occ && (nreg(n+2) == r.occ || nreg(n+2) == r.infini)) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : occurence min/max attendue %d\n", numlig, tmp->mPtr, n);
return DYN_ERR;
}
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcat(&e, valex, encours); // occmin
n++;
if(nreg(n) == r.infini)
dynConcatSz(&e, valex, "-1,", 3);
else
{
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcat(&e, valex, encours); // occmax
}
ent16 n1,n2,n3; char unefois[2] = {0};
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
while(n1 == r.car || n1 == r.hexa || ((n1 == r.car || n1 == r.hexa) && n2 == r.intervalle && (n3 == r.car || n3 == r.hexa)))
{
dynConcatSz(&e, valex, unefois, DYN_LGNONE);
if((n1 == r.car || n1 == r.hexa) && n2 == r.intervalle && (n3 == r.car || n3 == r.hexa))
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
if(n1 == 10)
dynConcat(&e, valex, tmp);
else
{
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
dynConcatSz(&e, valex, "-", 1);
n += 2;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
if(n3 == r.car)
dynConcat(&e, valex, tmp);
else
{
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
}
else if(n1 == r.car)
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(&e, valex, tmp);
}
else if(n1 == r.hexa)
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
unefois[0] = ':';
}
if(unefois[0] == 0)
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : caractere/intervalle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
if(n1 == r.fin) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : fin et/ou attendue\n", numlig, tmp->mPtr);
return DYN_ERR;
}
n += 2;
}
/* lecture nom regle en hexa */
dynField(&e, valex, tmp, 1, 1, cFM, cVM, 1);
dynIconv(&e, tmp, trav, "X");
trav->mPtr[trav->mLg - 1] = ','; /* exemple : begin,1,comment,2,... permet de faire un locate */
dynConcatSz(&e, trav, Int64ToSz(&e, nbres == 0 ? 1 : nbres, DYN_FALSE, 0), DYN_LGNONE);
dynStore(&e, resultat, 1, nbres == 0 ? 1 : nbres*2-1, trav, 10, ',');
/* */
dynField(&e, valex, tmp, 4, DYN_NONE, cFM, DYN_NONE, 1);
nbres = (nbres == 0 ? 2 : nbres + 1);
dynStoreSz(&e, resultat, nbres, DYN_NONE, tmp->mPtr, tmp->mLg, 10, DYN_NONE);
/* */
#undef nreg
return OK;
}
long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3)
{
dynSetLen(&e, elem2, 0); // token
dynSetLen(&e, elem3, 0); // numero
dynField(&e, resultat, elem1, 1, DYN_NONE, 10, DYN_NONE, 1); // ligne 1 = token,numero,token,numero,...
dynField(&e, resultat, elem1, 1, 1, 10, ';', 1); // ligne 1 = token,numero,token,numero,...;etat;etat;etat
//long nb = dynDcount(e, elem1, ',', DYN_NONE, DYN_NONE) / 2;
long nb = 0;
dynSetLen(&e, resultat, 0);
dynLet(&e, resultat, "/* ", 3);
// Pass1 : commentaire
dynRemove(&e, elem1, NULL, 0, DYN_TRUE);
while(dynRemove(&e, elem1, elem2, ',', DYN_FALSE) > -1 && dynRemove(&e, elem1, elem3, ',', DYN_FALSE) > -1)
@@ -255,7 +52,7 @@ long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3
dynConcatSz(&e, resultat, ",", DYN_LGNONE);
dynConcatSz(&e, resultat, elem3->mPtr, DYN_LGNONE);
}
dynConcatSz(&e, resultat, "\n\n", 2);
dynConcatSz(&e, resultat, " */\n\n", 5);
// Pass2 struct
nb = 0;
dynRemove(&e, elem1, NULL, 0, DYN_TRUE);
@@ -313,10 +110,14 @@ long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3
return OK;
}
long gen_h(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3)
long gen_h(Dynamic * resultat, Dynamic * elem1)
{
dynErase(&e, resultat, "\r"); /* nettoyage au cas ou fichier Windows */
dynChange(&e, resultat, "\n", "\\n", DYN_ALL);
dynChange(&e, resultat, "\n", "\\n\"\n\"", DYN_ALL);
/* */
dynLet(&e, elem1, "static char file[] = \"", DYN_LGNONE);
dynSetSubstr(&e, resultat, elem1, 0, 0, 1, DYN_NONE, cFM, DYN_NONE);
dynConcatSz(&e, resultat, "\";", 2);
return OK;
}
@@ -350,13 +151,12 @@ int main(int argc, char * argv[])
}
else
{
if(lire_regles_lex(&e, &regles, NULL) != DYN_OK)
if(lire_regles_lex(&e, &regles, "lexlex") != DYN_OK)
ret = -3;
}
if(ret == 0)
{
init_reg(&e, &regles, &elem1);
//printf("commentaire : %ld nomregle : %ld\n", r.commentaire, r.nomregle);
init_reg_lex(&e, &regles, &elem1); // elem1 = var tmp
//
dynErase(&e, &fichier, "\r");
dynRemove(&e, &fichier, NULL, 0, DYN_TRUE);
@@ -364,23 +164,26 @@ int main(int argc, char * argv[])
{
lex(&e, &regles, &ligne, &valex);
/* */
ret = parse(&valex, &resultat, &elem1, &elem2, &elem3);
ret = parse_lex(&e, &valex, &resultat, &elem1, &elem2, &elem3, 0); /* 0 : runtime off, printf ok */
/* */
//dynConvert(&e, &valex, sFM sVM, "\n|");
//printf("valex %s\n", valex.mPtr);//
}
printf("Resultat (ret=%d):\n%s\n", ret, resultat.mPtr);
if(ret == OK)
ret = compile_maj_etat(&e, &resultat, &elem1, &elem2, &elem3);
/* */
printf("Compile a rediriger dans un fichier (ret=%d):\n\n%s\n\n", ret, resultat.mPtr);
//
if(ret == 0)
if(ret == OK)
{
dynLet(&e, &fichier, resultat.mPtr, resultat.mLg); // sauvegarde
// generer le code C a copier/coller dans genw.c
ret = gen_c(&resultat, &elem1, &elem2, &elem3);
printf("\nCode C genere : \n%s\n", resultat.mPtr);
printf("Code C genere : \n\n%s\n", resultat.mPtr);
//
// generer le code C a copier/coller dans lex_files.h
ret = gen_h(&fichier, &elem1, &elem2, &elem3);
printf("\nCode H genere : \n%s\n", fichier.mPtr);
ret = gen_h(&fichier, &elem1);
printf("Code H genere, a copier dans lex_files.h (idem compile) : \n\n%s\n\n", fichier.mPtr);
}
}
dynFree(&e, &valex);
+717 -360
View File
File diff suppressed because it is too large. Load diff
+81 -9
View File
@@ -25,9 +25,19 @@
#include <string.h>
#include "langage.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* met a jour le minimum de <env> pour pouvoir utiliser <dynamic.h> sans erreur... */
void init_env(env * e)
WAPIDECL void init_env(env * e)
{
int i,j,k;
/* endianess */
@@ -55,7 +65,7 @@ void init_env(env * e)
e->sep_subfield = '\xFD'; // cVM
}
char * copy_nom(env * e, const char * s)
WAPIDECL char * copy_nom(env * e, const char * s)
{
e->nom64[0] = 0;
e->nom64[1] = 0;
@@ -66,7 +76,15 @@ char * copy_nom(env * e, const char * s)
return e->nom;
}
int modFnIs(env * e, const char * fn, int lg)
WAPIDECL char * raz_nom(env * e)
{
e->nom64[0] = 0;
e->nom64[1] = 0;
e->nom64[2] = 0;
return e->nom;
}
WAPIDECL int modFnIs(env * e, const char * fn, int lg)
{
// modifier l'endroit ou e->fn est mis a jour : verif fn64[0 1 2] est bien remis a zero avant la maj
ent64 f[3];
@@ -81,7 +99,7 @@ int modFnIs(env * e, const char * fn, int lg)
/* fonctions wrapper au cas ou on aurait besoin de ne plus utiliser certaines */
/* fonctions standards (malloc, etc.) */
void * memalloc(env * e, ent64 taille)
WAPIDECL void * memalloc(env * e, ent64 taille)
{
void * ptr;
taille += sizeof(ent64);
@@ -109,7 +127,7 @@ void * memalloc(env * e, ent64 taille)
}
}
void memfree(env * e, void * ptr)
WAPIDECL void memfree(env * e, void * ptr)
{
if(ptr != NULL)
{
@@ -129,7 +147,7 @@ void memfree(env * e, void * ptr)
}
}
void memcopie(void * dst, void * src, long nb)
WAPIDECL void memcopie(void * dst, void * src, long nb)
{
if(dst == src || nb <= 0)
return;
@@ -147,7 +165,55 @@ void memcopie(void * dst, void * src, long nb)
// for (char *p=src, *q=dst; --n>=0; ) q[n]=p[n]; // fin au debut
}
void hex(pointeur ch, int lg)
WAPIDECL void dynPrintfSz(env * e, const char * format, char * valeur)
{
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
if(valeur)
dynChange(e, &e->printf, PRINTF_MARK, valeur, DYN_ALL);
}
WAPIDECL void dynPrintfInt64(env * e, const char * format, ent64s valeur, long nb)
{
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
dynChange(e, &e->printf, PRINTF_MARK, Int64ToSz(e, valeur, DYN_TRUE, nb), DYN_ALL);
}
WAPIDECL void dynPrintfHex(env * e, const char * format, ent64 valeur, long nb)
{
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
char conv[17] = "0000000000000000";
conv[16] = 0;
dynConcatSz(e, &e->printf, (char *)format, DYN_LGNONE);
int i;
for(i = 15; i >=0 && valeur != 0; i--, valeur /= 16)
conv[i] = hex[valeur % 16];
//
if(nb > 0 && nb < 17)
nb = 16 - nb;
else
nb = i + 1;
dynChange(e, &e->printf, PRINTF_MARK, conv + nb, DYN_ALL);
}
WAPIDECL void dynPrintfConcatHexSz(env * e, char * valeur, long lg)
{
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
char car[3] = {0};
for(long i = 0; i < lg; i++)
{
car[0] = hex[((unsigned char)valeur[i]) >> 4];
car[1] = hex[((unsigned char)valeur[i]) & 15];
dynConcatSz(e, &e->printf, car, 2);
if(i % 32 == 31 && i < lg - 1)
dynConcatSz(e, &e->printf, "\n ", 4);
else if(i % 8 == 7 && i < lg - 1)
dynConcatSz(e, &e->printf, " | ", 3);
else
dynConcatSz(e, &e->printf, " ", 1);
}
}
WAPIDECL void hex(pointeur ch, int lg)
{
int i;
char c;
@@ -167,7 +233,7 @@ void hex(pointeur ch, int lg)
printf(" > %s\n", a);
}
void hex2(char * ch, int lg, int nbpl)
WAPIDECL void hex2(char * ch, int lg, int nbpl)
{
int i;
char c;
@@ -210,12 +276,18 @@ void hex2(char * ch, int lg, int nbpl)
printf(" (%6d) %s\n", i, a);
}
void hex3(const char * p, long lg)
WAPIDECL void hex3(const char * p, long lg)
{
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
// affiche en hexa la chaine sur une ligne
printf("=> ");
for(long i = 0; i < lg; i++)
{
printf("%c%c ", hex[((unsigned char)p[i]) >> 4], hex[((unsigned char)p[i]) & 15]);
if(i % 32 == 31 && i < lg - 1)
printf("\n ");
else if(i % 8 == 7 && i < lg - 1)
printf(" | ");
}
printf("\n");
}
+17 -9
View File
@@ -23,23 +23,31 @@
#ifndef GLOBAL_H
#define GLOBAL_H
#include "apidecl.h"
void init_env(env * e);
WAPIDECL void init_env(env * e);
char * copy_nom(env * e, const char * s);
int modFnIs(env * e, const char * fn, int lg);
WAPIDECL char * copy_nom(env * e, const char * s);
WAPIDECL char * raz_nom(env * e);
WAPIDECL int modFnIs(env * e, const char * fn, int lg);
/* ************************************************************************** */
/* fonctions wrapper au cas ou on aurait besoin de ne plus utiliser certaines */
/* fonctions standards (malloc, etc.) */
void * memalloc(env * e, ent64 taille);
void memfree(env * e, void * ptr);
void memcopie(void * dst, void * src, long nb);
WAPIDECL void * memalloc(env * e, ent64 taille);
WAPIDECL void memfree(env * e, void * ptr);
WAPIDECL void memcopie(void * dst, void * src, long nb);
void hex(pointeur ch, int lg);
void hex2(char * ch, int lg, int nbpl);
void hex3(const char * p, long lg);
#define PRINTF_MARK "\1"
WAPIDECL void dynPrintfSz(env * e, const char * format, char * valeur);
WAPIDECL void dynPrintfInt64(env * e, const char * format, ent64s valeur, long nb);
WAPIDECL void dynPrintfHex(env * e, const char * format, ent64 valeur, long nb);
WAPIDECL void dynPrintfConcatHexSz(env * e, char * valeur, long lg); // equiv hex3
WAPIDECL void hex(pointeur ch, int lg);
WAPIDECL void hex2(char * ch, int lg, int nbpl);
WAPIDECL void hex3(const char * p, long lg);
/* ************************************ */
#endif
+34
View File
@@ -0,0 +1,34 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
WAPIDECL void encodageMD2(env * e, var * entree, var * sortie);
WAPIDECL void encodageMD4(env * e, var * entree, var * sortie);
WAPIDECL void encodageMD5(env * e, var * entree, var * sortie);
WAPIDECL void encodageSha1(env * ctx, var * entree, var * sortie);
WAPIDECL void encodageAdler32(env * ctx, var * entree, var * sortie);
+156 -329
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,393 +25,220 @@
#include <time.h>
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#else
#include "windows.h" // TODO ici
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "hash.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
static void encodageMD2(char * entree, ent64 longueur, char * sortie)
{
unsigned char checksum[16] = {0};
unsigned char padding[16] = {0};
unsigned char buffer[48] = {0};
ent64 i, j, k;
static unsigned char tpi[]={ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115,
140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138,
23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121,
145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231,
191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207,
101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35,
221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244,
65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139,
227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248,
235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
unsigned char * p = (unsigned char *)entree;
unsigned char L = 0, T;
while(longueur >= 16)
{
for(i = 0; i < 16; i++)
{
buffer[16 + i] = *p++;
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
longueur -= 16;
}
if(longueur > 0)
{
memcpy(padding, p, longueur);
}
ent64 nb = 16 - longueur;
memset(padding + longueur, nb, nb);
// calcul MD2 sur dernier bloc avec padding
for(i = 0; i < 16; i++)
{
buffer[16 + i] = padding[i];
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
// calcul MD2 sur checksum
for(i = 0; i < 16; i++)
{
buffer[16 + i] = checksum[i];
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
/* fin du calcul md2 : en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i = 0, j = 0; i < 16; i++)
{
sortie[j++] = carhex[buffer[i] / 16];
sortie[j++] = carhex[buffer[i] % 16];
}
sortie[j] = 0;
}
static void majMD4(unsigned int * md4, unsigned int * buffer)
{
unsigned int A, B, C, D, tmp;
unsigned int buf[16];
unsigned char * octet;
ent64 i;
#define rot(T,s) (tmp = T, (tmp<<s) | (tmp>>(32-s)))
#define f(W,X,Y,Z,i,r) W = rot((W + ((X&Y) | ((~X)&Z)) + buf[i]),r)
#define g(W,X,Y,Z,i,r) W = rot(((W + ((X&Y) | (X&Z) | (Y&Z))) + buf[i] + 0x5A827999),r)
#define h(W,X,Y,Z,i,r) W = rot((W + (X^Y^Z) + buf[i] + 0x6ED9EBA1),r)
/* coder le buffer en little endian */
octet = (unsigned char *)buffer;
for(i=0; i<16; i++, octet+=4)
buf[i] = (*octet) | ((*(octet+1))<<8) | ((*(octet+2))<<16) | ((*(octet+3))<<24);
/* */
/* printf("%08x %08x\n",buffer[0], buf[0]); */
A = md4[0];
B = md4[1];
C = md4[2];
D = md4[3];
/* Round 1 */
f(A , B , C , D , 0 , 3);
f(D , A , B , C , 1 , 7);
f(C , D , A , B , 2 , 11);
f(B , C , D , A , 3 , 19);
f(A , B , C , D , 4 , 3);
f(D , A , B , C , 5 , 7);
f(C , D , A , B , 6 , 11);
f(B , C , D , A , 7 , 19);
f(A , B , C , D , 8 , 3);
f(D , A , B , C , 9 , 7);
f(C , D , A , B , 10 , 11);
f(B , C , D , A , 11 , 19);
f(A , B , C , D , 12 , 3);
f(D , A , B , C , 13 , 7);
f(C , D , A , B , 14 , 11);
f(B , C , D , A , 15 , 19);
/* Round 2 */
g(A , B , C , D , 0 , 3);
g(D , A , B , C , 4 , 5);
g(C , D , A , B , 8 , 9);
g(B , C , D , A , 12 , 13);
g(A , B , C , D , 1 , 3);
g(D , A , B , C , 5 , 5);
g(C , D , A , B , 9 , 9);
g(B , C , D , A , 13 , 13);
g(A , B , C , D , 2 , 3);
g(D , A , B , C , 6 , 5);
g(C , D , A , B , 10 , 9);
g(B , C , D , A , 14 , 13);
g(A , B , C , D , 3 , 3);
g(D , A , B , C , 7 , 5);
g(C , D , A , B , 11 , 9);
g(B , C , D , A , 15 , 13);
/* Round 3 */
h(A , B , C , D , 0 , 3);
h(D , A , B , C , 8 , 9);
h(C , D , A , B , 4 , 11);
h(B , C , D , A , 12 , 15);
h(A , B , C , D , 2 , 3);
h(D , A , B , C , 10 , 9);
h(C , D , A , B , 6 , 11);
h(B , C , D , A , 14 , 15);
h(A , B , C , D , 1 , 3);
h(D , A , B , C , 9 , 9);
h(C , D , A , B , 5 , 11);
h(B , C , D , A , 13 , 15);
h(A , B , C , D , 3 , 3);
h(D , A , B , C , 11 , 9);
h(C , D , A , B , 7 , 11);
h(B , C , D , A , 15 , 15);
/* */
md4[0] += A;
md4[1] += B;
md4[2] += C;
md4[3] += D;
}
void encodageMD4(char * entree, ent64 longueur, char * sortie)
{
unsigned char lg[8];
unsigned char buffer[64];
unsigned int md4[4]; // forcer sur 32 bits
ent64 i, j, k;
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
md4[0] = (unsigned int)0x67452301;
md4[1] = (unsigned int)0xefcdab89;
md4[2] = (unsigned int)0x98badcfe;
md4[3] = (unsigned int)0x10325476;
*(ent64 *)lg = (ent64)longueur * 8;
/* */
while(longueur >= 64)
{
majMD4(md4, (unsigned int *)entree);
entree += 64;
longueur -= 64;
}
/* traitement du dernier bloc */
/* ajouter 0x80 et dans les 8 derniers octets le nombre de bits du flux initial (unsigned long long) */
/* si pas assez de place, faire un nouveau bloc */
memset(buffer, 0, 64);
if(longueur > 0)
memcpy(buffer, entree, longueur);
buffer[longueur] = 128; /* 0x80 */
if(longueur <= 55)
{
/* un seul dernier bloc */
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, (unsigned int *)buffer);
}
else
{
/* 2 derniers blocs */
majMD4(md4, (unsigned int *)buffer);
/* */
memset(buffer, 0, 64);
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, (unsigned int *)buffer);
}
//
/* calcul md4 en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i=0, j=0, k=0; i<4; i++, j+=8, k+=4)
{
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie[j] = carhex[buffer[0]/16];
sortie[j+1] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie[j+2] = carhex[buffer[0]/16];
sortie[j+3] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie[j+4] = carhex[buffer[0]/16];
sortie[j+5] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
sortie[j+6] = carhex[buffer[0]/16];
sortie[j+7] = carhex[buffer[0]%16];
}
sortie[32] = 0;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// MD2(entree, resultat)
// MD4(entree, resultat)
//
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(p_etat == NULL)
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
exc = EX_MODETAT;
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "MD2", 3) == 0)
else if(modFnIs(e, "MD2", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD2(param1->mPtr, param1->lg, param2->mPtr);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD2(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "MD4", 3) == 0)
else if(modFnIs(e, "MD4", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD4(param1->mPtr, param1->lg, param2->mPtr);
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD4(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD5", 3))
{
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageMD5(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "Sha1", 4))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageSha1(e, paramPlaintext, paramHashedText);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "Adler32", 7))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
/* get param in the right order */
var * paramPlaintext = getParam(e, "plaintext", 9);
var * paramHashedText = getParam(e, "hashedText", 10);
if(paramPlaintext == NULL || paramHashedText == NULL)
exc = EX_MODPARAM;
else if(paramPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramHashedText->type != VAR_DYNAMIC)
var_let(e, paramHashedText, &e->int_dynamic, FALSE, FALSE);
encodageAdler32(e, paramPlaintext, paramHashedText);
}
}
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+717
View File
@@ -0,0 +1,717 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "hash.h"
#include "string.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ============ PRIVATE ===================================== */
static void majMD4(unsigned int * md4, pointeur buffer)
{
unsigned int A, B, C, D, tmp;
unsigned int buf[16];
unsigned char * octet;
ent64 i;
#define rot(T,s) (tmp = T, (tmp<<s) | (tmp>>(32-s)))
#define f(W,X,Y,Z,i,r) W = rot((W + ((X&Y) | ((~X)&Z)) + buf[i]),r)
#define g(W,X,Y,Z,i,r) W = rot(((W + ((X&Y) | (X&Z) | (Y&Z))) + buf[i] + 0x5A827999),r)
#define h(W,X,Y,Z,i,r) W = rot((W + (X^Y^Z) + buf[i] + 0x6ED9EBA1),r)
/* coder le buffer en little endian */
octet = buffer;
for(i=0; i<16; i++, octet+=4)
buf[i] = (*octet) | ((*(octet+1))<<8) | ((*(octet+2))<<16) | ((*(octet+3))<<24);
/* */
/* printf("%08x %08x\n",buffer[0], buf[0]); */
A = md4[0];
B = md4[1];
C = md4[2];
D = md4[3];
/* Round 1 */
f(A , B , C , D , 0 , 3);
f(D , A , B , C , 1 , 7);
f(C , D , A , B , 2 , 11);
f(B , C , D , A , 3 , 19);
f(A , B , C , D , 4 , 3);
f(D , A , B , C , 5 , 7);
f(C , D , A , B , 6 , 11);
f(B , C , D , A , 7 , 19);
f(A , B , C , D , 8 , 3);
f(D , A , B , C , 9 , 7);
f(C , D , A , B , 10 , 11);
f(B , C , D , A , 11 , 19);
f(A , B , C , D , 12 , 3);
f(D , A , B , C , 13 , 7);
f(C , D , A , B , 14 , 11);
f(B , C , D , A , 15 , 19);
/* Round 2 */
g(A , B , C , D , 0 , 3);
g(D , A , B , C , 4 , 5);
g(C , D , A , B , 8 , 9);
g(B , C , D , A , 12 , 13);
g(A , B , C , D , 1 , 3);
g(D , A , B , C , 5 , 5);
g(C , D , A , B , 9 , 9);
g(B , C , D , A , 13 , 13);
g(A , B , C , D , 2 , 3);
g(D , A , B , C , 6 , 5);
g(C , D , A , B , 10 , 9);
g(B , C , D , A , 14 , 13);
g(A , B , C , D , 3 , 3);
g(D , A , B , C , 7 , 5);
g(C , D , A , B , 11 , 9);
g(B , C , D , A , 15 , 13);
/* Round 3 */
h(A , B , C , D , 0 , 3);
h(D , A , B , C , 8 , 9);
h(C , D , A , B , 4 , 11);
h(B , C , D , A , 12 , 15);
h(A , B , C , D , 2 , 3);
h(D , A , B , C , 10 , 9);
h(C , D , A , B , 6 , 11);
h(B , C , D , A , 14 , 15);
h(A , B , C , D , 1 , 3);
h(D , A , B , C , 9 , 9);
h(C , D , A , B , 5 , 11);
h(B , C , D , A , 13 , 15);
h(A , B , C , D , 3 , 3);
h(D , A , B , C , 11 , 9);
h(C , D , A , B , 7 , 11);
h(B , C , D , A , 15 , 15);
/* */
md4[0] += A;
md4[1] += B;
md4[2] += C;
md4[3] += D;
}
/* ============ PUBLIC ===================================== */
WAPIDECL void encodageMD2(env * e, var * entree, var * sortie)
{
unsigned char checksum[16] = {0};
unsigned char padding[16] = {0};
unsigned char buffer[48] = {0};
ent64 i, j, k;
static unsigned char tpi[]={ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115,
140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138,
23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121,
145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231,
191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207,
101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35,
221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244,
65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139,
227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248,
235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
unsigned char * p = (unsigned char *)(entree->ptr);
unsigned char L = 0, T;
long longueur = entree->mLg;
while(longueur >= 16)
{
for(i = 0; i < 16; i++)
{
buffer[16 + i] = *p++;
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
longueur -= 16;
}
if(longueur > 0)
{
memcpy(padding, p, longueur);
}
ent64 nb = 16 - longueur;
memset(padding + longueur, nb, nb);
// calcul MD2 sur dernier bloc avec padding
for(i = 0; i < 16; i++)
{
buffer[16 + i] = padding[i];
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
// calcul MD2 sur checksum
for(i = 0; i < 16; i++)
{
buffer[16 + i] = checksum[i];
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
/* fin du calcul md2 : en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i = 0, j = 0; i < 16; i++)
{
sortie->ptr[j++] = carhex[buffer[i] / 16];
sortie->ptr[j++] = carhex[buffer[i] % 16];
}
dynSetLen(e, sortie, j); // len = 32 ici
}
WAPIDECL void encodageMD4(env * e, var * entree, var * sortie)
{
unsigned char lg[8];
unsigned char buffer[64];
unsigned int md4[4]; // forcer sur 32 bits
ent64 i, j, k;
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
md4[0] = (unsigned int)0x67452301;
md4[1] = (unsigned int)0xefcdab89;
md4[2] = (unsigned int)0x98badcfe;
md4[3] = (unsigned int)0x10325476;
long longueur = entree->mLg;
*(ent64 *)lg = (ent64)longueur * 8;
/* */
pointeur p = entree->ptr;
while(longueur >= 64)
{
majMD4(md4, p);
p += 64;
longueur -= 64;
}
/* traitement du dernier bloc */
/* ajouter 0x80 et dans les 8 derniers octets le nombre de bits du flux initial (unsigned long long) */
/* si pas assez de place, faire un nouveau bloc */
memset(buffer, 0, 64);
if(longueur > 0)
memcpy(buffer, p, longueur);
buffer[longueur] = 128; /* 0x80 */
if(longueur <= 55)
{
/* un seul dernier bloc */
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, buffer);
}
else
{
/* 2 derniers blocs */
majMD4(md4, buffer);
/* */
memset(buffer, 0, 64);
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, buffer);
}
//
/* calcul md4 en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i=0, j=0, k=0; i<4; i++, j+=8, k+=4)
{
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j] = carhex[buffer[0]/16];
sortie->ptr[j+1] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j+2] = carhex[buffer[0]/16];
sortie->ptr[j+3] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j+4] = carhex[buffer[0]/16];
sortie->ptr[j+5] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
sortie->ptr[j+6] = carhex[buffer[0]/16];
sortie->ptr[j+7] = carhex[buffer[0]%16];
}
dynSetLen(e, sortie, 32);
}
/* MD5/SHA1 - RFC 1321 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define ROTATE_RIGHT(x, n) (((x) >> (n)) | ((x) << (32-(n))))
#define ROTATE_RIGHT_64(x, n) (((x) >> (n)) | ((x) << (64-(n))))
#define SHIFT_RIGHT(x, n) ((x) >> (n))
#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define CH(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define PARITY(x, y, z) ((x) ^ (y) ^ (z))
WAPIDECL void encodageMD5(env * e, var * entree, var * sortie)
{
ent32 a, b, c, d, s0, s1, s2, s3, i, x[16];
unsigned char buffer[64];
/* */
s0 = 0x67452301;
s1 = 0xefcdab89;
s2 = 0x98badcfe;
s3 = 0x10325476;
/* */
long len64 = entree->mLg % 64;
long nb64 = entree->mLg / 64;
long der1 = 0, der2 = 0, der3 = 0;
if(len64 < 56)
{
// dernier bloc : len64(entree) 1(128) 55-len64(0) 8(mLg)
der1 = ++nb64;
}
else
{
// avant dernier bloc : len64(entree) 1(128) 63-len64(0)
// dernier bloc : 0(56) 8(mLg)
der2 = ++nb64;
der3 = ++nb64;
}
ent64 nb = (ent64)(entree->mLg * 8); /* en bits */
pointeur p = entree->ptr;
/* pour chaque bloc de 64 octets (512 bits) - little endian */
for(long cpt = 1; cpt <= nb64; cpt++)
{
if(cpt == der1)
{
// dernier bloc cas modulo < 56
memset(buffer, 0, 64);
if(len64 > 0)
memcpy(buffer, p, len64);
buffer[len64] = 128;
buffer[56] = (nb) & 0xff;
buffer[57] = (nb >> 8) & 0xff;
buffer[58] = (nb >> 16) & 0xff;
buffer[59] = (nb >> 24) & 0xff;
buffer[60] = (nb >> 32) & 0xff;
buffer[61] = (nb >> 40) & 0xff;
buffer[62] = (nb >> 48) & 0xff;
buffer[63] = (nb >> 56) & 0xff;
p = buffer;
}
else if(cpt == der2)
{
// avant dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
memcpy(buffer, p, len64);
buffer[len64] = 128;
p = buffer;
}
else if (cpt == der3)
{
// dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
buffer[56] = (nb) & 0xff;
buffer[57] = (nb >> 8) & 0xff;
buffer[58] = (nb >> 16) & 0xff;
buffer[59] = (nb >> 24) & 0xff;
buffer[60] = (nb >> 32) & 0xff;
buffer[61] = (nb >> 40) & 0xff;
buffer[62] = (nb >> 48) & 0xff;
buffer[63] = (nb >> 56) & 0xff;
p = buffer;
}
/* deplier la boucle ? */
for (i = 0; i < 16; i++)
{
x[i] = ((ent32)(*p++));
x[i] |= (((ent32)(*p++)) << 8);
x[i] |= (((ent32)(*p++)) << 16);
x[i] |= (((ent32)(*p++)) << 24);
}
//hex(p, 64);
/* */
a = s0;
b = s1;
c = s2;
d = s3;
/* Round 1 */
FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x02441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[ 6], S34, 0x04881d05); /* 44 */
HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
/* */
s0 += a;
s1 += b;
s2 += c;
s3 += d;
}
p = sortie->ptr; /* 16 octets en hexa */
char hexa[16] = "0123456789abcdef";
/* */
*p++ = hexa[(s0 >> 4) & 0xf];
*p++ = hexa[(s0) & 0xf];
*p++ = hexa[(s0 >> 12) & 0xf];
*p++ = hexa[(s0 >> 8) & 0xf];
*p++ = hexa[(s0 >> 20) & 0xf];
*p++ = hexa[(s0 >> 16) & 0xf];
*p++ = hexa[(s0 >> 28) & 0xf];
*p++ = hexa[(s0 >> 24) & 0xf];
/* */
*p++ = hexa[(s1 >> 4) & 0xf];
*p++ = hexa[(s1) & 0xf];
*p++ = hexa[(s1 >> 12) & 0xf];
*p++ = hexa[(s1 >> 8) & 0xf];
*p++ = hexa[(s1 >> 20) & 0xf];
*p++ = hexa[(s1 >> 16) & 0xf];
*p++ = hexa[(s1 >> 28) & 0xf];
*p++ = hexa[(s1 >> 24) & 0xf];
/* */
*p++ = hexa[(s2 >> 4) & 0xf];
*p++ = hexa[(s2) & 0xf];
*p++ = hexa[(s2 >> 12) & 0xf];
*p++ = hexa[(s2 >> 8) & 0xf];
*p++ = hexa[(s2 >> 20) & 0xf];
*p++ = hexa[(s2 >> 16) & 0xf];
*p++ = hexa[(s2 >> 28) & 0xf];
*p++ = hexa[(s2 >> 24) & 0xf];
/* */
*p++ = hexa[(s3 >> 4) & 0xf];
*p++ = hexa[(s3) & 0xf];
*p++ = hexa[(s3 >> 12) & 0xf];
*p++ = hexa[(s3 >> 8) & 0xf];
*p++ = hexa[(s3 >> 20) & 0xf];
*p++ = hexa[(s3 >> 16) & 0xf];
*p++ = hexa[(s3 >> 28) & 0xf];
*p++ = hexa[(s3 >> 24) & 0xf];
/* */
dynSetLen(e, sortie, 32);
}
WAPIDECL void encodageSha1(env * ctx, var * entree, var * sortie)
{
ent32 a, b, c, d, e, aNext, h0, h1, h2, h3, h4, t, w[80], k0, k1, k2, k3;
unsigned char buffer[64];
/* */
h0 = 0x67452301;
h1 = 0xefcdab89;
h2 = 0x98badcfe;
h3 = 0x10325476;
h4 = 0xc3d2e1f0;
/* */
k0 = 0x5a827999;
k1 = 0x6ed9eba1;
k2 = 0x8f1bbcdc;
k3 = 0xca62c1d6;
/* */
long len64 = entree->mLg % 64;
long nb64 = entree->mLg / 64;
long der1 = 0, der2 = 0, der3 = 0;
if(len64 < 56)
{
// dernier bloc : len64(entree) 1(128) 55-len64(0) 8(mLg)
der1 = ++nb64;
}
else
{
// avant dernier bloc : len64(entree) 1(128) 63-len64(0)
// dernier bloc : 0(56) 8(mLg)
der2 = ++nb64;
der3 = ++nb64;
}
ent64 nb = (ent64)(entree->mLg * 8); /* en bits */
pointeur p = entree->ptr;
/* pour chaque bloc de 64 octets (512 bits) - big endian */
for(long cpt = 1; cpt <= nb64; cpt++)
{
if(cpt == der1)
{
// dernier bloc cas modulo < 56
memset(buffer, 0, 64);
if(len64 > 0)
memcpy(buffer, p, len64);
buffer[len64] = 128;
buffer[63] = (nb) & 0xff;
buffer[62] = (nb >> 8) & 0xff;
buffer[61] = (nb >> 16) & 0xff;
buffer[60] = (nb >> 24) & 0xff;
buffer[59] = (nb >> 32) & 0xff;
buffer[58] = (nb >> 40) & 0xff;
buffer[57] = (nb >> 48) & 0xff;
buffer[56] = (nb >> 56) & 0xff;
p = buffer;
}
else if(cpt == der2)
{
// avant dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
memcpy(buffer, p, len64);
buffer[len64] = 128;
p = buffer;
}
else if (cpt == der3)
{
// dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
buffer[63] = (nb) & 0xff;
buffer[62] = (nb >> 8) & 0xff;
buffer[61] = (nb >> 16) & 0xff;
buffer[60] = (nb >> 24) & 0xff;
buffer[59] = (nb >> 32) & 0xff;
buffer[58] = (nb >> 40) & 0xff;
buffer[57] = (nb >> 48) & 0xff;
buffer[56] = (nb >> 56) & 0xff;
p = buffer;
}
/* */
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
/* */
/* deplier la boucle ? */
for (t = 0; t < 80; t++)
{
if(t < 16)
{
w[t] = (((ent32)(*p++)) << 24);
w[t] |= (((ent32)(*p++)) << 16);
w[t] |= (((ent32)(*p++)) << 8);
w[t] |= ((ent32)(*p++));
}
else
{
w[t] = w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16];
w[t] = ROTATE_LEFT(w[t], 1);
}
aNext = ROTATE_LEFT(a, 5) + e + w[t];
if(t < 20)
aNext += CH(b, c, d) + k0;
else if(t < 40)
aNext += PARITY(b, c, d) + k1;
else if(t < 60)
aNext += MAJ(b, c, d) + k2;
else
aNext += PARITY(b, c, d) + k3;
e = d;
d = c;
c = ROTATE_LEFT(b, 30);
b = a;
a = aNext;
}
/* */
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
p = sortie->ptr; /* 20 octets en hexa */
char hexa[16] = "0123456789abcdef";
/* */
*p++ = hexa[(h0 >> 28) & 0xf];
*p++ = hexa[(h0 >> 24) & 0xf];
*p++ = hexa[(h0 >> 20) & 0xf];
*p++ = hexa[(h0 >> 16) & 0xf];
*p++ = hexa[(h0 >> 12) & 0xf];
*p++ = hexa[(h0 >> 8) & 0xf];
*p++ = hexa[(h0 >> 4) & 0xf];
*p++ = hexa[(h0) & 0xf];
/* */
*p++ = hexa[(h1 >> 28) & 0xf];
*p++ = hexa[(h1 >> 24) & 0xf];
*p++ = hexa[(h1 >> 20) & 0xf];
*p++ = hexa[(h1 >> 16) & 0xf];
*p++ = hexa[(h1 >> 12) & 0xf];
*p++ = hexa[(h1 >> 8) & 0xf];
*p++ = hexa[(h1 >> 4) & 0xf];
*p++ = hexa[(h1) & 0xf];
/* */
*p++ = hexa[(h2 >> 28) & 0xf];
*p++ = hexa[(h2 >> 24) & 0xf];
*p++ = hexa[(h2 >> 20) & 0xf];
*p++ = hexa[(h2 >> 16) & 0xf];
*p++ = hexa[(h2 >> 12) & 0xf];
*p++ = hexa[(h2 >> 8) & 0xf];
*p++ = hexa[(h2 >> 4) & 0xf];
*p++ = hexa[(h2) & 0xf];
/* */
*p++ = hexa[(h3 >> 28) & 0xf];
*p++ = hexa[(h3 >> 24) & 0xf];
*p++ = hexa[(h3 >> 20) & 0xf];
*p++ = hexa[(h3 >> 16) & 0xf];
*p++ = hexa[(h3 >> 12) & 0xf];
*p++ = hexa[(h3 >> 8) & 0xf];
*p++ = hexa[(h3 >> 4) & 0xf];
*p++ = hexa[(h3) & 0xf];
/* */
*p++ = hexa[(h4 >> 28) & 0xf];
*p++ = hexa[(h4 >> 24) & 0xf];
*p++ = hexa[(h4 >> 20) & 0xf];
*p++ = hexa[(h4 >> 16) & 0xf];
*p++ = hexa[(h4 >> 12) & 0xf];
*p++ = hexa[(h4 >> 8) & 0xf];
*p++ = hexa[(h4 >> 4) & 0xf];
*p++ = hexa[(h4) & 0xf];
/* */
dynSetLen(ctx, sortie, 40);
/* */
a = b = c = d = e = h0 = h1 = h2 = h3 = h4 = 0;
memset(buffer, 0, 64);
}
WAPIDECL void encodageAdler32(env * ctx, var * entree, var * sortie)
{
ent32 s1 = 1, s2 = 0, mod = 65521;
unsigned char * p = entree->ptr;
long lg = entree->mLg;
for(long i = 0; i < lg; i++, p++)
s2 = (s2 + (s1 = ((s1 + *p) % mod))) % mod; /* TODO tester perfs avec modulo fait tous les 5802 octets */
s2 = (s2 << 16) | s1;
/* */
p = sortie->ptr; /* 4 octets en hexa */
char hexa[16] = "0123456789abcdef";
*p++ = hexa[(s2 >> 28) & 0xf];
*p++ = hexa[(s2 >> 24) & 0xf];
*p++ = hexa[(s2 >> 20) & 0xf];
*p++ = hexa[(s2 >> 16) & 0xf];
*p++ = hexa[(s2 >> 12) & 0xf];
*p++ = hexa[(s2 >> 8) & 0xf];
*p++ = hexa[(s2 >> 4) & 0xf];
*p++ = hexa[(s2) & 0xf];
dynSetLen(ctx, sortie, 8);
}
+177 -21
View File
@@ -27,15 +27,64 @@
#include "langage.h"
#include "var.h"
#include "hashtable.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
// =============== PRIVATE ========================================================================
static ent64 fmix64(ent64 h)
{
h ^= h >> 33;
h *= 0xff51afd7ed558ccdull;
h ^= h >> 33;
h *= 0xc4ceb9fe1a85ec53ull;
h ^= h >> 33;
return h;
}
static entry * calc_entry(char * val, var * varht)
{
/* fonctionne avec des noms de 24 octets max (val) */
ent64 hash;
/* algo de D. B e r n s t e i n / M u r m u r h a s h 6 4 */
/* autre algo */
if(0)
{
ent64 * p = (ent64 *)val;
ent64 h = 0x9e3779b97f4a7c15ull;
hash = h;
hash ^= *p++;
hash *= h;
hash ^= *p++;
hash *= h;
hash ^= *p;
hash *= h;
/* SplitMix64 */
hash ^= hash >> 30;
hash *= 0xbf58476d1ce4e5b9ull;
hash ^= hash >> 27;
hash *= 0x94d049bb133111ebull;
hash ^= hash >> 31;
}
/* */
if(0)
{
ent64 * p = (ent64 *)val;
ent64 h = 0x9e3779b97f4a7c15ull;
hash = h;
hash ^= fmix64((*p++) + h);
hash ^= fmix64((*p++) + 0x517cc1b727220a95ull);
hash ^= fmix64((*p) + 0x6eed0e9da4d94a4full);
// si longueur connue : mettre en plus la ligne suivante
//hash ^= fmix64(len * 0x9e3779b97f4a7c15ull);
hash = fmix64(hash);
}
/* */
if(0) {
ent64 * p = (ent64 *)val;
ent64 k = *p++;
@@ -60,12 +109,12 @@ static entry * calc_entry(char * val, var * varht)
hash ^= k;
hash *= m;
}
/* */
/* algo de D. B e r n s t e i n / M u r m u r h a s h 6 4 */
if(1) {
hash = 5381;
for(int iCle = 0; iCle < 24; iCle++)
if(val[iCle])
hash = hash + (hash<<5) + val[iCle]; /* hash*33 */
hash = hash + (hash << 5) + val[iCle]; /* hash * 33 */
else
break; // stop au premier \0
}
@@ -74,7 +123,7 @@ static entry * calc_entry(char * val, var * varht)
// =============== PUBLIC ========================================================================
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
{
/* READ renvoi le ptr sur la var (ne fait pas une copie de la var)
WRITE copie la var (si pas trouve ou trouve mais pointeurs differents)
@@ -88,7 +137,13 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
if(varht == NULL || v == NULL || nom == NULL)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
{
if((varht = (var *)varht->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
/* chaque groupe : | nom1 ... 0 (24) | var1 (40) | nom2 ... 0 (24) | var2 (40) | */
@@ -119,17 +174,19 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
pentry->nom2 = 0;
pentry->nom3 = 0;
pentry->content.type = 0;
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return;
}
if(action == HASH_WRITE) /* write */
{
/* ecraser la var presente (et liberer), sauf si meme var : NON car si type different => KO !! et d'ailleurs, est-ce utile ici puisque même pointeur ?? */
/* ecraser la var presente (et liberer), sauf si meme var : NON car si type different => KO !! et d'ailleurs, est-ce utile ici puisque meme pointeur ?? */
if(*v != (var *)&pentry->content)
{
/* liberer pentry->content ; si PARAM, libere la var pointee + copie de la var */
var_let(e, &pentry->content, *v, TRUE, FALSE); /* verifier que TRUE et FALSE sont ok ici !!! */
}
((entry *)varht->ptr)->pvar = &pentry->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
}
return;
}
@@ -149,7 +206,7 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
{
*v = NULL;
/* renvoyer la premiere entree libre trouvee, l'entree PAS la var (si NULL, il faudra rappeler do) */
((entry *)varht->ptr)->pvar = pfree == NULL ? NULL : &pfree->content;
((entry *)varht->ptr)->pvar = (var *)pfree;
}
/* si action = 2 delete et pas trouve : RAS */
if(action == HASH_WRITE) /* write */
@@ -172,16 +229,44 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
pfree->content.type = VAR_NULL;
var_let(e, &pfree->content, *v, FALSE, FALSE); /* copie de la var */
((entry *)varht->ptr)->pvar = &pfree->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
//printf("hashwrite non trouve %s %p -> %p (ad e->int_dynamic %p)\n", nom, *v, &pfree->content, &e->int_dynamic);
}
}
var * hashtable_lastitemwritten(var * varht)
WAPIDECL var * hashtable_writeinfirstfreeentry(env * e, var * varht, char * nom, var * v)
{
if(varht == NULL || v == NULL || nom == NULL)
return NULL;
if(varht->type == VAR_PARAM)
if((varht = (var *)varht->ptr) == NULL) /* travailler avec la var pointee ! */
return NULL;
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return NULL;
/* */
entry * pfree = (entry *)(((entry *)varht->ptr)->pvar);
if(pfree == NULL)
{
/* securite : faire HASH_WRITE */
hashtable_do(e, HASH_WRITE, varht, copy_nom(e, nom), &v);
return ((entry *)varht->ptr)->pvar; /* last item written */
}
/* */
pfree->nom1 = *(ent64 *)nom;
pfree->nom2 = *((ent64 *)nom + 1);
pfree->nom3 = *((ent64 *)nom + 2);
var_let(e, &pfree->content, v, FALSE, FALSE); /* copie de la var */
((entry *)varht->ptr)->pvar = &pfree->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return &pfree->content;
}
WAPIDECL var * hashtable_lastitemwritten(var * varht)
{
return ((entry *)varht->ptr)->pvar;
}
void hashtable_select(env * e, var * varht)
WAPIDECL void hashtable_select(env * e, var * varht)
{
/* les 4 variables necessaires seront mises dans le groupe 0, premiere entree (celle servant au chainage) */
/* dans la variable (content, inutilise) : */
@@ -197,10 +282,11 @@ void hashtable_select(env * e, var * varht)
pvar->ptr = (pointeur)(pentry+1); /* pentry */
}
int hashtable_next(env * e, var * varht, char * nom, var ** v)
WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v)
{
var * pvar;
entry * pentry;
if(((entry *)varht->ptr)->content.ptr == NULL) return FALSE; /* write/delete sur la hash durant le select : arret ! */
/* ne fait pas une copie de la variable en retour, mais renvoie un pointeur dans la hash !! */
for(pvar = &((entry *)varht->ptr)->content; pvar->type < varht->modulo; pvar->type++)
{
@@ -236,7 +322,7 @@ int hashtable_next(env * e, var * varht, char * nom, var ** v)
return FALSE;
}
void hashtable_free_ovf(env *e, var * varht)
WAPIDECL void hashtable_free_ovf(env *e, var * varht)
{
/* libere les overflow de la hash table */
/* pour chaque entree, chainage avant puis liberation en revenant en arriere */
@@ -259,7 +345,7 @@ void hashtable_free_ovf(env *e, var * varht)
/* reste a liberer le bloc primaire de la hashtable */
}
void hashtable_clear(env * e, var * varht)
WAPIDECL void hashtable_clear(env * e, var * varht)
{
var * pvar;
int suivrepar = TRUE;
@@ -271,11 +357,11 @@ void hashtable_clear(env * e, var * varht)
hashtable_free_ovf(e, varht);
/* raz contenu */
memset(varht->ptr, 0, varht->modulo * varht->separateur);
/* raz ptr par securite */
hashtable_select(e, varht);
/* raz ptr par securite (utile ??) */
//hashtable_select(e, varht);
}
long hashtable_count(env *e, var * varht)
WAPIDECL long hashtable_count(env *e, var * varht)
{
long nb = 0;
var * pvar;
@@ -284,11 +370,68 @@ long hashtable_count(env *e, var * varht)
while(hashtable_next(e, varht, e->nom, &pvar))
nb++;
/* raz ptr par securite */
hashtable_select(e, varht);
//hashtable_select(e, varht);
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return nb;
}
void hashtable_printdebug(env * e, var * varht, int detail)
WAPIDECL void hashtable_serialize(env * e, var * varht, var * out)
{
/* >>> format (ignorer sub/null/buffer/param), point d'entree = hash
N:nom\n
number\n
D:lg:nom\n
dynamic\n (lg ne tient pas compte du \n)
+:nom\n
<contenu hash/objet>
-:\n (fin hash)
S:nom()\n (que le nom de la sub)
*/
if(varht == NULL || out == NULL) return;
if((varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT) || out->type != VAR_DYNAMIC) return;
/* */
var * v;
hashtable_select(e, varht);
while(hashtable_next(e, varht, raz_nom(e), &v))
{
if(v->type == VAR_NUMBER)
{
dynConcatSz(e, out, "N:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
dynConcatSz(e, out, NumberToSz(e, v->num, NULL, NULL), DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
}
else if (v->type == VAR_DYNAMIC)
{
dynConcatSz(e, out, "D:", 2);
dynConcatSz(e, out, Int64ToSz(e, v->mLg, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, out, ":", 1);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
dynConcat(e, out, v);
dynConcatSz(e, out, "\n", 1);
}
else if (v->type == VAR_SUBROUTINE)
{
dynConcatSz(e, out, "S:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "()\n", 3);
}
else if(v->type == VAR_HASHTABLE || v->type == VAR_OBJECT)
{
dynConcatSz(e, out, "+:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
/* */
hashtable_serialize(e, v, out);
/* */
dynConcatSz(e, out, "-:\n", 3);
}
}
}
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
{
entry * pentry; /* pointe sur une entree */
entry * pchain; /* pointe sur la premiere du groupe, servant au chainage */
@@ -301,9 +444,18 @@ void hashtable_printdebug(env * e, var * varht, int detail)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
if(varht == NULL)
return;
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
printf("hashtable modulo=%lld separateur=%lld (n=%lld)\n", varht->modulo, varht->separateur, varht->separateur/sizeof(entry));
if(e->demon)
{
dynPrintfInt64(e, "hashtable modulo=" PRINTF_MARK " separateur=", varht->modulo, 0);
dynPrintfInt64(e, PRINTF_MARK " (n=", varht->separateur, 0);
dynPrintfInt64(e, PRINTF_MARK ")\n", varht->separateur/sizeof(entry), 0);
}
else
printf("hashtable modulo=%lld separateur=%lld (n=%lld)\n", varht->modulo, varht->separateur, varht->separateur/sizeof(entry));
/* */
occ = 0;
tot = 0;
@@ -341,7 +493,7 @@ void hashtable_printdebug(env * e, var * varht, int detail)
else
printf("%c", e->var_car[pentry->content.type % 10]);
/* */
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, "_class", 6) == 0 && ! ptrClass)
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, GUV_CLASS, 6) == 0 && ! ptrClass)
ptrClass = pentry->content.mPtr;
/* */
occ += sizeof(entry);
@@ -355,7 +507,11 @@ void hashtable_printdebug(env * e, var * varht, int detail)
pchain = (entry *)((ent64)pchain_first + varht->separateur);
}
if(ptrClass)
printf("_class : %s\n", ptrClass);
{
dynLet(e, &e->tmp_dynamic, ptrClass, DYN_LGNONE);
dynReplace(e, &e->tmp_dynamic, cFM, ':');
printf("%s %s\n", GUV_CLASS, e->tmp_dynamic.mPtr);
}
printf("taille totale=%lld, occupee=%lld (taux %lld%%), nb item=%lld\n", tot, occ, occ * 100 / tot, nb);
}
+13 -8
View File
@@ -23,15 +23,20 @@
#ifndef HASHTABLE_H
#define HASHTABLE_H
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
void hashtable_select(env * e, var * varht);
int hashtable_next(env * e, var * varht, char * nom, var ** v);
void hashtable_free_ovf(env *e, var * varht);
void hashtable_clear(env *e, var * varht);
long hashtable_count(env *e, var * varht);
var * hashtable_lastitemwritten(var * varht);
#include "apidecl.h"
void hashtable_printdebug(env * e, var * varht, int detail);
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
WAPIDECL void hashtable_select(env * e, var * varht);
WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v);
WAPIDECL void hashtable_free_ovf(env *e, var * varht);
WAPIDECL void hashtable_clear(env *e, var * varht);
WAPIDECL long hashtable_count(env *e, var * varht);
WAPIDECL var * hashtable_lastitemwritten(var * varht);
WAPIDECL var * hashtable_writeinfirstfreeentry(env * e, var * varht, char * nom, var * v);
WAPIDECL void hashtable_serialize(env * e, var * varht, var * out);
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail);
/* ********************************************** */
#endif
+68
View File
@@ -0,0 +1,68 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
// --- gestion protocole http
typedef struct {
int state; /* etat de decodage des trames http : 0 entete a lire, 1 en cours lecture entete, 2 lecture corps, 3 lecture corps mode chunk */
ent64s lengthToRead; /* longueur de donnees (corps) restant a lire */
ent64s chunkLength;
Dynamic header; /* liste des entetes http <1,x> nom entete (minuscule) <2, x> valeur, le decodage de la premiere ligne est mis ici : http_method http_path http_vers */
Dynamic content; /* corps du message http */
Dynamic line, tmp; /* buffer de lecture d'une ligne, variable de travail */
Dynamic methodList; /* liste des methodes http supportees */
int error;
} modCtxHttp;
enum {
/* state */
HTTPSTATE_HEADERTOREAD = 0,
HTTPSTATE_READINGHEADER = 1,
HTTPSTATE_READINGCONTENT = 2,
HTTPSTATE_READINGCHUNKEDCONTENT = 3,
/* codes d'erreur */
HTTP_METHOD_KO = 1,
HTTP_METHOD_GET_MISSING = 2,
HTTP_INCORRECT_LENGTH = 3,
HTTP_COLON_MISSING = 4,
HTTP_CHUNK_BODY_CRLF_MISSING = 5,
HTTP_STATUS_KO = 6,
/* code retour */
HTTP_REQUEST_ERROR = -1,
HTTP_REQUEST_INPROGRESS = 0,
HTTP_REQUEST_COMPLETE = 1,
HTTP_REQUEST_EXPECTCONTINUE = 2
};
WAPIDECL void InitHttp(env * e, modCtxHttp * ctx);
WAPIDECL void FreeHttp(env * e, modCtxHttp * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data, int isRequest);
WAPIDECL long MakeExpect100(env * e, modCtxHttp * ctx, Dynamic * reponse);
WAPIDECL long MakeResponse(env * e, modCtxHttp * ctx, long cr, Dynamic * reponse);
+229
View File
@@ -0,0 +1,229 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "http.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modCtxHttp ctxHttp;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_HTTP_ERROR = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Protocol error"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
InitHttp(e, &p_etat->ctxHttp);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
FreeHttp(e, &p_etat->ctxHttp);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "getRequest", 10))
{
/* get param in the right order */
var * paramInput = getParam(e, "inputData", 9);
var * paramContent = getParam(e, "content", 7);
var * paramReturn = getParam(e, "returnCode", 10);
if(paramInput == NULL || paramContent == NULL || paramReturn == NULL)
exc = EX_MODPARAM;
else if(paramInput->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramReturn->type != VAR_NUMBER)
var_let(e, paramReturn, &e->int_number, FALSE, FALSE);
/* */
long cr = ExtractMessage(e, &p_etat->ctxHttp, paramInput, TRUE);
/* */
if(cr == HTTP_REQUEST_COMPLETE)
dynConcat(e, paramContent, &p_etat->ctxHttp.content);
else if(cr == HTTP_REQUEST_ERROR)
p_etat->error = p_etat->ctxHttp.error; /* A REVOIR !! */
/* */
paramReturn->num = cr * NUM_FACTEUR;
}
}
/* --------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getResponse", 11))
{
/* get param in the right order */
var * paramInput = getParam(e, "inputData", 9);
var * paramContent = getParam(e, "content", 7);
var * paramReturn = getParam(e, "returnCode", 10);
if(paramInput == NULL || paramContent == NULL || paramReturn == NULL)
exc = EX_MODPARAM;
else if(paramInput->type != VAR_DYNAMIC || paramContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramReturn->type != VAR_NUMBER)
var_let(e, paramReturn, &e->int_number, FALSE, FALSE);
/* */
long cr = ExtractMessage(e, &p_etat->ctxHttp, paramInput, FALSE);
/* */
if(cr == HTTP_REQUEST_COMPLETE)
dynSetAs(e, paramContent, &p_etat->ctxHttp.content);
else if(cr == HTTP_REQUEST_ERROR)
p_etat->error = p_etat->ctxHttp.error; /* A REVOIR !! */
/* */
paramReturn->num = cr * NUM_FACTEUR;
}
}
/* --------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getHeader", 9))
{
/* get param in the right order */
var * paramHeader = getParam(e, "headerList", 10);
if(paramHeader == NULL)
exc = EX_MODPARAM;
else
{
if(paramHeader->type != VAR_DYNAMIC)
var_let(e, paramHeader, &e->int_dynamic, FALSE, FALSE);
/* */
dynSetAs(e, paramHeader, &p_etat->ctxHttp.header);
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+365
View File
@@ -0,0 +1,365 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "http.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
#define CRLF "\r\n"
#define LEN_CRLF 2
/* ***** PUBLIC *************** */
WAPIDECL void InitHttp(env * e, modCtxHttp * ctx)
{
ctx->error = 0;
ctx->state = HTTPSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
dynInit(e, &ctx->header, DYN_LGMIN);
dynInit(e, &ctx->content, DYN_LGMIN);
dynInit(e, &ctx->line, DYN_LGMIN);
dynInit(e, &ctx->tmp, DYN_LGMIN);
dynInit(e, &ctx->methodList, DYN_LGMIN);
dynLet(e, &ctx->methodList, "GET" sFM "HEAD" sFM "POST" sFM "OPTIONS" sFM "CONNECT" sFM "TRACE" sFM "PUT" sFM "PATCH" sFM "DELETE", DYN_LGNONE); // laisser GET en premier sinon KO
}
WAPIDECL void FreeHttp(env * e, modCtxHttp * ctx)
{
dynFree(e, &ctx->header);
dynFree(e, &ctx->content);
dynFree(e, &ctx->line);
dynFree(e, &ctx->tmp);
dynFree(e, &ctx->methodList);
}
WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data, int isRequest)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
/* isRequest est TRUE pour decoder une requete http, FALSE pour decoder une reponse http */
if(ctx->state == HTTPSTATE_HEADERTOREAD || ctx->state == HTTPSTATE_READINGHEADER)
{
for(;;)
{
long ind = dynIndexSz(e, data, CRLF, LEN_CRLF, 1);
if(ind < 0)
return HTTP_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
dynSetLen(e, &ctx->line, 0);
if(ind > 0)
dynSubstr(e, data, &ctx->line, 0, ind, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, ind + LEN_CRLF);
/* ici <ctx->line> contient la ligne d'entete et <data> est a jour avec les donnees suivantes */
/* */
if(ctx->state == HTTPSTATE_HEADERTOREAD)
{
/* premiere ligne du protocole : principale difference selon le type : Request-line or Status-line */
if(isRequest)
{
long posMethod;
dynField(e, &ctx->line, &ctx->tmp, 1, DYN_NONE, ' ', DYN_NONE, 1); // method
if((posMethod = dynLocateSz(e, &ctx->methodList, ctx->tmp.mPtr, cFM, DYN_NONE, DYN_NONE)) == DYN_NOTLOCATED)
{
ctx->error = HTTP_METHOD_KO;
return HTTP_REQUEST_ERROR;
}
dynSetLen(e, &ctx->header, 0); // vider le header
dynInsSz(e, &ctx->header, 1, 1, "http_method", 11, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 2, DYN_NONE, ' ', DYN_NONE, 1); // path
dynInsSz(e, &ctx->header, 1, 1, "http_path", 9, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 3, DYN_NONE, ' ', DYN_NONE, 1);
if(ctx->tmp.mLg == 0)
{
/* quand http version absent : version http 0.9 implicite, GET seul autorise, pas d'entete et pas de ligne vide => corps (https://fr.wikipedia.org/wiki/Hypertext_Transfer_Protocol) */
if(posMethod != 1)
{
ctx->error = HTTP_METHOD_GET_MISSING; /* http 0.9 GET seul autorise */
return HTTP_REQUEST_ERROR;
}
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynInsSz(e, &ctx->header, 2, 1, "HTTP/0.9", 8, cFM, cVM);
dynSetLen(e, &ctx->content, 0);
return HTTP_REQUEST_COMPLETE; /* requete terminee */
}
else
{
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
}
/* */
ctx->state = HTTPSTATE_READINGHEADER;
ctx->lengthToRead = 0;
}
else
{
/* response */
dynField(e, &ctx->line, &ctx->tmp, 1, DYN_NONE, ' ', DYN_NONE, 1); // http/version
dynSetLen(e, &ctx->header, 0); // vider le header
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
/* */
dynField(e, &ctx->line, &ctx->tmp, 2, DYN_NONE, ' ', DYN_NONE, 1); // code statut
ent64s status = dynSzToNum(e, ctx->tmp.mPtr, DYN_FALSE, 3, (long *)&ctx->tmp.mInternal);
if(status < 100 || status > 599 || ctx->tmp.mLg != 3)
{
ctx->error = HTTP_STATUS_KO;
return HTTP_REQUEST_ERROR;
}
dynInsSz(e, &ctx->header, 1, 1, "http_status", 11, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
/* */
dynField(e, &ctx->line, &ctx->tmp, 3, DYN_NONE, ' ', DYN_NONE, 1); // description
/* */
ctx->state = HTTPSTATE_READINGHEADER;
ctx->lengthToRead = 0;
}
}
else
{
/* entetes a lire */
if(ctx->line.mLg == 0)
{
// fin des entetes
dynSetLen(e, &ctx->content, 0);
long posExpect = dynLocateSz(e, &ctx->header, "expect", cVM, 1, cFM);
if(posExpect != DYN_NOTLOCATED)
{
dynField(e, &ctx->header, &ctx->tmp, 2, posExpect, cFM, cVM, 1);
if(dynCompare(e, &ctx->tmp, CMP_EQ, "100-continue", 12))
{
/* envoyer une reponse 100 expect-continue avant de lire le corps */
ctx->state = HTTPSTATE_READINGCONTENT;
return HTTP_REQUEST_EXPECTCONTINUE;
}
}
if(dynLocateSz(e, &ctx->header, "http_chunked", cVM, 1, cFM) == DYN_NOTLOCATED)
{
if(ctx->lengthToRead == 0)
{
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_COMPLETE; /* pas de contenu ici */
}
ctx->state = HTTPSTATE_READINGCONTENT;
}
else
{
ctx->lengthToRead = 0;
ctx->chunkLength = -1; // indique que la longueur a lire est a prendre dans le contenu, car mode chunked
ctx->state = HTTPSTATE_READINGCHUNKEDCONTENT;
}
break;
}
else
{
/* lecture de l'entete */
dynBegin(e, &ctx->line);
if(dynNext(e, &ctx->line, &ctx->tmp, ':') > -1)
{
dynCut(e, &ctx->line, ctx->line.mInternal + 1);
// nom entete en minuscule
dynErase(e, &ctx->tmp, " ");
str2lower(e, &ctx->tmp);
if(dynLocateSz(e, &ctx->header, ctx->tmp.mPtr, cVM, 1, cFM) != DYN_NOTLOCATED)
continue; // entete deja memorisee, ignorer le doublon
// valeur
dynTrimSpace(e, &ctx->line);
// tmp = nom entete, line = valeur entete
dynIns(e, &ctx->header, 1, 1, &ctx->tmp, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->line, cFM, cVM);
// mode chunk ?
if(dynCompare(e, &ctx->tmp, CMP_EQ, "transfer-encoding", 17) && dynCompare(e, &ctx->line, CMP_EQ, "chunked", 7))
{
dynInsSz(e, &ctx->header, 1, 1, "http_chunked", 12, cFM, cVM);
dynInsSz(e, &ctx->header, 2, 1, "1", 1, cFM, cVM);
}
if(dynCompare(e, &ctx->tmp, CMP_EQ, "content-length", 14))
{
ctx->lengthToRead = dynToNum(e, &ctx->line, DYN_FALSE, 0); /* longueur negative cause une erreur */
if(ctx->line.mInternal == DYN_ERR)
{
ctx->error = HTTP_INCORRECT_LENGTH; // erreur de conversion du content-length : ingorer et on continue
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_ERROR;
}
}
}
else
{
/* erreur de syntaxe dans l'entete */
ctx->error = HTTP_COLON_MISSING;
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_ERROR;
}
}
}
} /* endless for */
}
/* */
if(ctx->state == HTTPSTATE_READINGCONTENT)
{
// lecture corps, ctx->lengthToRead est > 0 ici
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return HTTP_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues */
dynConcatSz(e, &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
ctx->state = HTTPSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
return HTTP_REQUEST_COMPLETE;
}
}
/* */
if(ctx->state == HTTPSTATE_READINGCHUNKEDCONTENT)
{
// chunkLength : -1 longueur chunk a lire, > 0 chunk a lire ou en cours de lecture (+ CRLF de fin : dans lengthToRead)
for(;;)
{
if(ctx->chunkLength < 0)
{
long ind = dynIndexSz(e, data, CRLF, LEN_CRLF, 1);
if(ind < 0)
return HTTP_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
dynSetLen(e, &ctx->line, 0);
if(ind > 0)
dynSubstr(e, data, &ctx->line, 0, ind, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, ind + LEN_CRLF);
/* ici <ctx->line> contient la ligne de longueur du chunk */
/* longueur du chunk en hexa */
ctx->chunkLength = hex2num(e, &ctx->line); // quid erreur de conversion ?
ctx->lengthToRead = ctx->chunkLength + 2; // integre le CRLF de fin de chunk
}
if(ctx->chunkLength >= 0)
{
if(data->mLg == 0)
return HTTP_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
/* */
/* donnees du chunk */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return HTTP_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues, controle CRLF de fin du chunk */
dynConcatSz(e, &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
if(strncmp(ctx->content.mPtr + ctx->content.mLg - LEN_CRLF, CRLF, LEN_CRLF) == 0)
{
dynSetLen(e, &ctx->content, ctx->content.mLg - LEN_CRLF);
if(ctx->chunkLength == 0)
{
/* dernier chunk (vide) recu : message complet */
ctx->state = HTTPSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
return HTTP_REQUEST_COMPLETE;
}
else
{
/* fin du chunk, attente du suivant */
ctx->chunkLength = -1;
}
}
else
{
/* erreur de formatage du chunk : le corps ne se termine pas par CRLF */
ctx->error = HTTP_CHUNK_BODY_CRLF_MISSING;
ctx->state = HTTPSTATE_HEADERTOREAD;
return HTTP_REQUEST_ERROR;
}
}
}
} /* endless for */
}
/* */
return HTTP_REQUEST_ERROR;
}
WAPIDECL long MakeExpect100(env * e, modCtxHttp * ctx, Dynamic * reponse)
{
dynLet(e, reponse, "HTTP/1.1 100 Continue" CRLF CRLF, DYN_LGNONE);
return OK;
}
WAPIDECL long MakeResponse(env * e, modCtxHttp * ctx, long cr, Dynamic * reponse)
{
// en versoin 0.9, pas d'entete => directement le contenu !
//if((pos = dynLocateSz(e, &ctx->header, "http_version", cVM, 1, cFM)) == DYN_NOTLOCATED)
// else
// dynField(e, &ctx->header, &ctx->tmp, 2, pos, cFM, cVM, 1);
// si tmp == "HTTP/0.9" : contenu direct
//
//header.SetAs("HTTP/1.1 ");
//if(cr == '0' || cr == '1' || cr == '2')
// header.AppendString("200 OK"); // controles ont ete faits
//else if(cr == 'R') // URI ou corps de la requête incorrect
// header.AppendString("400 Bad Request");
//else if(cr == 'S')
// header.AppendString("500 Internal Server Error");
//else if(cr == 'S')
// header.AppendString("501 Not Implemented");
//else
// header.AppendString("500 Internal Server Error"); // erreur par defaut
////
//if(mKeepAlive)
// header.AppendString("\r\nConnection: keep-alive");
//else
// header.AppendString("\r\nConnection: close");
////
//header.AppendString("\r\nContent-Type: ");
//if(contentType == 'j')
// header.AppendString("application/json");
//else
// header.AppendString("application/octet-stream\r\nContent-Length: "); // valeur par defaut 'generique', ne doit pas arriver
//header.AppendString(reponse.GetContentSize());
//header.AppendString("\r\n\r");
////
//reponse.SetDelimiter(cLF);
//reponse.InsertField(1, header);
return OK;
}
+9 -2
View File
@@ -28,7 +28,7 @@ void instr_unassemble(env * e, pointeur debutBin, ent64 nolig)
/* special 2 bytes w opcode */
case IN_COMP:
d1 = lire8(p);
if(d1 < CMP_EQ || d1 > CMP_NOT)
if(d1 < CMP_EQ || d1 > CMP_FOR)
printf("??? (%d)", d1);
else
{
@@ -66,13 +66,20 @@ void instr_unassemble(env * e, pointeur debutBin, ent64 nolig)
case IN_PNAM:
case IN_CLIB:
case IN_PVAI:
case IN_CPSH:
case IN_CPAN:
case IN_CPHN:
case IN_PHDE:
case IN_PIDE:
case IN_PHDH:
case IN_PIDH:
case IN_PHDO:
case IN_PIDO:
case IN_PHDN:
case IN_PIDN:
case IN_PHDV:
case IN_PIDV:
case IN_PVHD:
case IN_PVID:
case IN_DEXH:
case IN_DEXI:
case IN_DESH:
+46 -17
View File
@@ -27,6 +27,7 @@
/* ************************************ */
/* AJOUT D'UNE INSTRUCTION
- instr.h : ci-dessous, 2 constantes + ajout a libInstr
- instr.c : ajout constante, si besoin, dans instr_unassemble
- langage.c : ajout dans le tableau de function instr + dans le commentaire en dessous,
ajouter la function instr_xxx
- assembler.c : ajout switch de la function assembler,
@@ -38,16 +39,16 @@
char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW" "PART" "RETN"
"CALL" "PARM" "SUBR" "COMP" "JMPF" "JMPT" "ADDN" "SBCN" "MULN" "DIVN"
"INTE" "FRAC" "NEGN" "ABSN" "MODL" "PSHC" "PSHV" "POPV" "PVAR" "PVAH"
"WRIT" "WRLN" "DSET" "DEXV" "DCMP" "DSTO" "VLET" "DCAT" "DTON" "NTOD"
"WRIT" "WRLN" "DSET" "DEXV" "DCMP" "DSTO" "LETV" "DCAT" "DTON" "NTOD"
"DELE" "HLET" "CLAS" "NLET" "INCL" "PNAM" "PSH0" "PSH1" "PSH2" "PSH3"
"PSH4" "PSH5" "PSH6" "PSH7" "PSH8" "PSH9" "PSHA" "PROG" "BACK" "CLIB"
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPSH" "RETT"
"PSH4" "PSH5" "PSH6" "PSH7" "PSH8" "PSH9" "PSHA" "SQRT" "IEXP" "CLIB" /* 50-59 */
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPAN" "RETT"
"SELE" "RNXT" "CPHA" "PHDE" "PIDE" "PHDH" "PIDH" "PHDO" "PIDO" "PHDS"
"PIDS" "TYPE" "ROUN" "LENG" "COUN" "DCOF" "FIEL" "INDX" "SRCH" "CHNG"
"FMTA" "INSE" "REMV" "TONU" "TOST" "CCAT" "SSTR" "SSEP" "FLDF" "FLDS" /* 0-99 */
"DCOS" "FMTT" "FMTS" "SCHS" "INSS" "REMS" "DEXH" "DEXI" "PREC" "DESV"
"DESH" "DESI" "DEZV" "DEZH" "DEZI" "SDBG" "xxxx" "xxxx" "xxxx" "xxxx" /* 110-119 */
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"DESH" "DESI" "DEZV" "DEZH" "DEZI" "SDBG" "PHDN" "PIDN" "SADV" "VLET" /* 110-119 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "SSRC" "SSCS" "CPHH" "CPHN" "xxxx" /* 128 */
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
@@ -60,9 +61,9 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" /* 200-249 */
"xxxx" "LIBR" "ENDL" "TEST" "ENDS" "ENDP"};
"PROG" "LIBR" "ENDL" "BACK" "ENDS" "ENDP"};
char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "FOR"};
#define IS_VERS "\x00"
#define IN_VERS 0
@@ -139,8 +140,8 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
#define IN_DCMP 34
#define IS_DSTO "\x23"
#define IN_DSTO 35
#define IS_VLET "\x24"
#define IN_VLET 36
#define IS_LETV "\x24"
#define IN_LETV 36
#define IS_DCAT "\x25"
#define IN_DCAT 37
#define IS_DTON "\x26"
@@ -183,10 +184,10 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
#define IN_PSH9 55
#define IS_PSHA "\x38"
#define IN_PSHA 56
#define IS_PROG "\x39"
#define IN_PROG 57
#define IS_BACK "\x3A"
#define IN_BACK 58
#define IS_SQRT "\x39"
#define IN_SQRT 57
#define IS_IEXP "\x3A"
#define IN_IEXP 58
#define IS_CLIB "\x3B"
#define IN_CLIB 59
@@ -206,8 +207,8 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
#define IN_PSHT 66
#define IS_CRAZ "\x43"
#define IN_CRAZ 67
#define IS_CPSH "\x44"
#define IN_CPSH 68
#define IS_CPAN "\x44"
#define IN_CPAN 68
#define IS_RETT "\x45"
#define IN_RETT 69
@@ -307,13 +308,41 @@ char libComp[9 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT"};
#define IN_DEZI 114
#define IS_SDBG "\x73"
#define IN_SDBG 115
#define IS_PHDN "\x74"
#define IN_PHDN 116
#define IS_PIDN "\x75"
#define IN_PIDN 117
#define IS_SADV "\x76"
#define IN_SADV 118
#define IS_VLET "\x77"
#define IN_VLET 119
#define IS_PHDV "\x78"
#define IN_PHDV 120
#define IS_PIDV "\x79"
#define IN_PIDV 121
#define IS_HCOU "\x7A"
#define IN_HCOU 122
#define IS_PVHD "\x7B"
#define IN_PVHD 123
#define IS_PVID "\x7C"
#define IN_PVID 124
#define IS_SSRC "\x7D"
#define IN_SSRC 125
#define IS_SSCS "\x7E"
#define IN_SSCS 126
#define IS_CPHH "\x7F"
#define IN_CPHH 127
#define IS_CPHN "\x80"
#define IN_CPHN 128
#define IS_PROG "\xFA"
#define IN_PROG 250
#define IS_LIBR "\xFB"
#define IN_LIBR 251
#define IS_ENDL "\xFC"
#define IN_ENDL 252
#define IS_TEST "\xFD"
#define IN_TEST 253
#define IS_BACK "\xFD"
#define IN_BACK 253
#define IS_ENDS "\xFE"
#define IN_ENDS 254
#define IS_ENDP "\xFF"
+44 -20
View File
@@ -1,3 +1,25 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
@@ -29,32 +51,34 @@ typedef struct
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMODJSON_MEM 106
#define EXMODJSON_DECODE_INCORRECT_CHAR 101
#define EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED 102
#define EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED 103
#define EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED 104
#define EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER 105
#define EXMODJSON_DECODE_UNTERMINATED_STRING 107
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT 108
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY 109
#define EXMODJSON_DECODE_UNEXPECTED_KEY 110
#define EXMODJSON_DECODE_UNEXPECTED_VALUE 111
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT 112
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT 113
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY 114
#define EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON 115
enum {
EXMODJSON_DECODE_INCORRECT_CHAR = 1,
EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED = 2,
EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED = 3,
EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED = 4,
EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER = 5,
EXMODJSON_MEM = 6,
EXMODJSON_DECODE_UNTERMINATED_STRING = 7,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT = 8,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY = 9,
EXMODJSON_DECODE_UNEXPECTED_KEY = 10,
EXMODJSON_DECODE_UNEXPECTED_VALUE = 11,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT = 12,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT = 13,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY = 14,
EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON = 15
};
/*
Le decodage a besoin de mEncodeCle mEncodeValeur et la position de l'erreur si erreur (3 parametres ; en entree la position le flag "NoDQuote"). L'erreur est le code retour.
L'encodage a besoin de mEncode, mId, flag NoDQuote (3 parametres)
*/
int jsonInit(env * e, modContextJson * ctx);
int jsonEnd(env * e, modContextJson * ctx);
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonInit(env * e, modContextJson * ctx);
WAPIDECL int jsonEnd(env * e, modContextJson * ctx);
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * json, var * cle, var * valeur);
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * cle, var * valeur, var * printable);
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * content, var * done);
/*
+160 -108
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,151 +27,203 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "json.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextJson jsonCtx;
} modEtat;
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#define MOD_VERSION 1
#ifndef UNIX
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
/* codes erreur dans dans json.h */
EXMOD_NB = 15
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Unexpected character",
"True keywoed expected",
"False keyword expected",
"Null keyword expected",
"Unpexted character while decoding number", // 5
"Memory error",
"End of string expected",
"Unexpected start object character",
"Unexpected start array character",
"Unexpected key", // 10
"Unexpected value",
"Unexpected next character",
"Unexpected end object character",
"Unexpected end array character",
"Unexpected end of json" // 15
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
}
}
else if(strncmp(e->fn, "end", 3) == 0)
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "decode", 6) == 0)
else if(modFnIs(e, "decode", 6))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
/* get param in the right order */
var * paramJsonText = getParam(e, "jsonText", 8);
var * paramExtractedKey = getParam(e, "extractedKey", 12);
var * paramExtractedValue = getParam(e, "extractedValue", 14);
if(paramJsonText == NULL || paramExtractedKey == NULL || paramExtractedValue == NULL)
exc = EX_MODPARAM;
else if(paramJsonText->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* param2 and param3 are dynamic (output) ; param1 must be a dynamic (input) */
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // bad type of parameter 1 or 2 or 3
else
// param3 = 1 for no double-quoted json (key and string value, except if <space> is present in value) ; future use
exc = setError(p_etat, jsonDecode(e, &p_etat->jsonCtx, param1, param2, param3));
if(paramExtractedKey->type != VAR_DYNAMIC)
var_let(e, paramExtractedKey, &e->int_dynamic, FALSE, FALSE);
if(paramExtractedValue->type != VAR_DYNAMIC)
var_let(e, paramExtractedValue, &e->int_dynamic, FALSE, FALSE);
exc = setError(p_etat, jsonDecode(e, &p_etat->jsonCtx, paramJsonText, paramExtractedKey, paramExtractedValue));
}
}
else if(modFnIs(e, "print", 5))
{
/* get param in the right order */
var * paramExtractedKey = getParam(e, "extractedKey", 12);
var * paramExtractedValue = getParam(e, "extractedValue", 14);
var * paramPrettyPrint = getParam(e, "prettyPrint", 11);
if(paramExtractedKey == NULL || paramExtractedValue == NULL || paramPrettyPrint == NULL)
exc = EX_MODPARAM;
else if(paramExtractedKey->type != VAR_DYNAMIC || paramExtractedValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramPrettyPrint->type != VAR_DYNAMIC)
var_let(e, paramPrettyPrint, &e->int_dynamic, FALSE, FALSE);
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, paramExtractedKey, paramExtractedValue, paramPrettyPrint));
}
}
else if(modFnIs(e, "treeFetch", 9))
{
/* get param in the right order */
var * paramFetchParameters = getParam(e, "fetchParameters", 15);
var * paramDone = getParam(e, "done", 4);
if(paramFetchParameters == NULL || paramDone == NULL)
exc = EX_MODPARAM;
else if(paramFetchParameters->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
if(paramDone->type != VAR_NUMBER)
var_let(e, paramDone, &e->int_number, FALSE, FALSE);
exc = setError(p_etat, jsonTreeFetch(e, &p_etat->jsonCtx, paramFetchParameters, paramDone));
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "print", 5) == 0)
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else
{
/* param2 and param3 are dynamic (output) ; param1 must be a dynamic (input) */
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM; // bad type of parameter 1 or 2 or 3
else
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, param1, param2, param3));
}
}
else if(strncmp(e->fn, "treeFetch", 9) == 0)
{
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else
{
/* param1 must be a hash table (input) */
if(param1->type != VAR_HASHTABLE || param2->type != VAR_NUMBER)
exc = EX_MODPARAM; // bad type of parameter 1
else
exc = setError(p_etat, jsonTreeFetch(e, &p_etat->jsonCtx, param1, param2, param3));
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+88 -54
View File
@@ -1,3 +1,25 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -7,8 +29,16 @@
#include "var.h"
#include "hashtable.h"
#define LF 10
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ------------------------------------------ */
#define CAR_DQUOTE '"'
#define CAR_MARQUE_CLE ':'
#define CAR_DEBUT_OBJET '{'
@@ -25,23 +55,27 @@
#define STR_FIN_TABLEAU "]"
#define STR_SUIVANT ","
#define DEBUT_FICHIER 0
#define VALEUR_CHAINE 1
#define VALEUR_NOMBRE 2
#define VALEUR_CLE 3
#define DEBUT_OBJET 4
#define FIN_OBJET 5
#define DEBUT_TABLEAU 6
#define FIN_TABLEAU 7
#define SUIVANT 8
#define FIN_FICHIER 9
enum {
DEBUT_FICHIER = 0,
VALEUR_CHAINE = 1,
VALEUR_NOMBRE = 2,
VALEUR_CLE = 3,
DEBUT_OBJET = 4,
FIN_OBJET = 5,
DEBUT_TABLEAU = 6,
FIN_TABLEAU = 7,
SUIVANT = 8,
FIN_FICHIER = 9,
#define ENCODE_OK 1
#define ENCODE_ERREUR 0
ENCODE_OK = 1,
ENCODE_ERREUR = 0,
LF = 10
};
/* =================================================================================== */
/* --------- JSON C --------- */
/* --------- PRIVATE --------- */
static void ConcatValue(env * e, modContextJson * ctx, char c)
{
char car[2];
@@ -611,7 +645,7 @@ static int GetNextTreeFetch(env * e, treefetch * tree)
*/
/* =================== PUBLIC ========================== */
int jsonInit(env * e, modContextJson * ctx)
WAPIDECL int jsonInit(env * e, modContextJson * ctx)
{
int cr = OK;
//cr += dynInit(e, &ctx->mKeyList, DYN_LGMIN);
@@ -636,7 +670,7 @@ int jsonInit(env * e, modContextJson * ctx)
return (cr == OK ? OK : EXMODJSON_MEM);
}
int jsonEnd(env * e, modContextJson * ctx)
WAPIDECL int jsonEnd(env * e, modContextJson * ctx)
{
//dynFree(e, &ctx->mKeyList);
//dynFree(e, &ctx->mCurrentKey);
@@ -648,76 +682,76 @@ int jsonEnd(env * e, modContextJson * ctx)
return OK;
}
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * json, var * cle, var * valeur)
{
return Decode(e, ctx, param1->mPtr, param2, param3);
return Decode(e, ctx, json->mPtr, cle, valeur);
}
int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * cle, var * valeur, var * printable)
{
char value[4] = " : \0", path = '/', index = '@';
//
return MakePrintable(e, ctx, param1, param2, param3, path, index, value);
return MakePrintable(e, ctx, printable, cle, valeur, path, index, value);
}
int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * content, var * done)
{
// KeyList, CurrentKey, Name, Value, DecodeCle, DecodeValue; // Dynamic
// KeyField, KeyItem, KeyCount, ItemCount, Id, Parent, IdKey, ParentKey, ValuePresent; // Number
treefetch tree; // contexte specifique a chaque appel
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeCle"), &tree.DecodeCle);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeValue"), &tree.DecodeValue);
hashtable_do(e, HASH_READ, content, copy_nom(e, "DecodedKey"), &tree.DecodeCle);
hashtable_do(e, HASH_READ, content, copy_nom(e, "DecodedValue"), &tree.DecodeValue);
if(tree.DecodeCle == NULL || tree.DecodeValue == NULL)
{
param2->num = NUM_UN;
done->num = NUM_UN;
return OK; // TODO erreur
}
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyList"), &tree.KeyList);
if(tree.KeyList == NULL)
{
// init vars
var * v = &e->int_dynamic;
dynSetLen(e, &e->int_dynamic, 0);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyList"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "CurrentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Name"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Value"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyList"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "CurrentKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Name"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Value"), &v);
v = &e->int_number;
v->num = 1;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyField"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyItem"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Id"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyField"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyItem"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Id"), &v);
v->num = 0;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Parent"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "Parent"), &v);
v->num = dynDcount(e, tree.DecodeCle, cVM, DYN_NONE, DYN_NONE);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyCount"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "KeyCount"), &v);
v->num = dynDcount(e, tree.DecodeCle, cSVM, 1, cVM);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ItemCount"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "IdKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ParentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ValuePresent"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "ItemCount"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "IdKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "ParentKey"), &v);
hashtable_do(e, HASH_WRITE, content, copy_nom(e, "ValuePresent"), &v);
}
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CurrentKey"), &tree.CurrentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Name"), &tree.Name);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Value"), &tree.Value);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, content, copy_nom(e, "CurrentKey"), &tree.CurrentKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Name"), &tree.Name);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Value"), &tree.Value);
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyField"), &tree.KeyField);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyItem"), &tree.KeyItem);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyCount"), &tree.KeyCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ItemCount"), &tree.ItemCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Id"), &tree.Id);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Parent"), &tree.Parent);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "IdKey"), &tree.IdKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ParentKey"), &tree.ParentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ValuePresent"), &tree.ValuePresent);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyField"), &tree.KeyField);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyItem"), &tree.KeyItem);
hashtable_do(e, HASH_READ, content, copy_nom(e, "KeyCount"), &tree.KeyCount);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ItemCount"), &tree.ItemCount);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Id"), &tree.Id);
hashtable_do(e, HASH_READ, content, copy_nom(e, "Parent"), &tree.Parent);
hashtable_do(e, HASH_READ, content, copy_nom(e, "IdKey"), &tree.IdKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ParentKey"), &tree.ParentKey);
hashtable_do(e, HASH_READ, content, copy_nom(e, "ValuePresent"), &tree.ValuePresent);
/* */
//hashtable_printdebug(e, param1, 1);
//hashtable_printdebug(e, content, 1);
if(GetNextTreeFetch(e, &tree)) // TRUE = pas fini
param2->num = NUM_ZERO; // var <fin>
done->num = NUM_ZERO; // var <fin>
else
param2->num = NUM_UN;
done->num = NUM_UN;
return OK;
}
+2186 -931
View File
File diff suppressed because it is too large. Load diff
+147 -92
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -23,16 +23,20 @@
#ifndef LANGAGE_H
#define LANGAGE_H
#define VERSION 1 // version "max" gere du pcode => version du "langage"
enum {
VERSION = 1 // version "max" gere du pcode => version du "langage"
};
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define W_LITTLE_ENDIAN 1
#define W_BIG_ENDIAN 0
#define W_DEFAULT_ENDIAN 2 // celle de la plateforme d'execution
enum {
W_LITTLE_ENDIAN = 1,
W_BIG_ENDIAN = 0,
W_DEFAULT_ENDIAN = 2 // celle de la plateforme d'execution
};
typedef unsigned char octet;
typedef octet * pointeur; /* et pas "void *" ... */
@@ -44,14 +48,9 @@ typedef int ent32s;
typedef long long ent64s;
typedef unsigned short ent16;
#ifndef UNIX
typedef ent64s ent128s; // sous windows, pas de __int128 : TODO a changer pour des calculs corrects
#else
typedef __int128 ent128s; // temporaire pour les calculs intermediaires (multiplication)
#endif
#define NUM_MIN -999999999999999999ll
#define NUM_MAX 999999999999999999ll
#define ENT64_MAX 999999999999999999ull /* 18 chiffres dont 5 decimales version non signee pour calcul */
#define NUM_PI 314159ll
#define NUM_MOINSUN -100000ll
#define NUM_ZERO 0ll
@@ -65,6 +64,7 @@ typedef __int128 ent128s; // temporaire pour les calculs intermediaires
#define NUM_HUIT 800000ll
#define NUM_NEUF 900000ll
#define NUM_FACTEUR 100000ll /* facteur multiplicatif/diviseur pour virgule fixe (5 decimales ici) */
#define FACTEUR 100000 /* constante int 32 bits */
#define NUM_ENTIER 13 /* nb chiffres partie entiere maxi */
#define NUM_DECIMAL 5 /* nb de decimales maxi, mais precision max = NUM_DECIMAL - 1 (4 decimales ici) */
@@ -73,25 +73,28 @@ typedef ent64s number; /* 8 octets signes, virgule fixe */
/* les variables ne sont pas typees : elles peuvent changer de type au fur et a mesure des affectations */
/* type 0 indique que l'emplacement n'a pas ete utilise encore : place disponible */
#define VAR_NULL 1 /* variable declaree mais pas encore affectee d'une valeur */
#define VAR_NUMBER 2 /* et @number */
#define VAR_SUBROUTINE 3
#define VAR_PARAM 4 /* adresse de la "vraie" variable, 1 seul niveau d'indirection, travail toujours sur la var "pointee" */
#define VAR_DYNAMIC 5 /* et @string */
#define VAR_HASHTABLE 6
#define VAR_OBJECT 7 /* idem hashtable mais en objet : seule diff. element "_class" cree dans la table (interne) */
#define VAR_BUFFER 8 /* usage interne : pile calcul + pile appel sub (autre ? buffer circulaire ptr read/write) */
#define VAR_NB 8
#define VAR_EMPTY 0 /* retour @empty */
enum {
VAR_NULL = 1, /* variable declaree mais pas encore affectee d'une valeur */
VAR_NUMBER = 2, /* et @number */
VAR_SUBROUTINE = 3,
VAR_PARAM = 4, /* adresse de la "vraie" variable, 1 seul niveau d'indirection, travail toujours sur la var "pointee" */
VAR_DYNAMIC = 5, /* et @string */
VAR_HASHTABLE = 6,
VAR_OBJECT = 7, /* idem hashtable mais en objet : seule diff. element "_class" cree dans la table (interne) */
VAR_BUFFER = 8, /* usage interne : pile calcul + pile appel sub (autre ? buffer circulaire ptr read/write) */
VAR_NB = 8,
VAR_EMPTY = 0, /* retour @empty fonction type(expr) */
#define VAR_UNDECLARED -1
VAR_UNDECLARED = 0, /* cas de retour si pas de var dans "typeof var1.var2.var3" */
#define CP_WIN1252 1252
#define CP_8859_1 28591
#define CP_8859_15 28605
#define CP_UTF8 65001
WCP_ASCII = 0, /* pour valeur par defaut */
WCP_WIN1252 = 1252,
WCP_8859_1 = 28591,
WCP_8859_15 = 28605,
WCP_UTF8 = 65001,
#define CP_DEFAULT CP_WIN1252 // UTF8 ??
WCP_DEFAULT = WCP_ASCII // WIN1252 ? UTF8 ?
};
typedef struct {
//union {
@@ -127,7 +130,7 @@ typedef struct {
ent64 write; /* buffer */
ent64 misc; /* hashtable/objet et subroutine (si_except) */
ent64s mInternal; /* pour dynamic */
pointeur etat; /* pour module, etat utilise d'appels en appels */
pointeur etat; /* pour module (SUB), etat utilise d'appels en appels ; pour VAR_PARAM indique si variable est un element de hash (PVAH) */
};
} var; /* 40 octets */
@@ -146,7 +149,7 @@ typedef struct {
};
union {
ent64 nom3;
var * pvar; /* sert a renvoyer l'adresse de la var suite a WRITE */
var * pvar; /* sert a renvoyer l'adresse de la var suite a WRITE / adresse de la premiere entry libre si READ non trouve */
};
var content;
} entry; /* 64 octets = 24 + var(40) */
@@ -163,8 +166,6 @@ typedef struct {
v->ptr v->ptr v->misc
*/
#define BUF_LGMINBLOC 16384 /* multiple de 32 sinon pile d'elements 8 et 16 octets KO, lgmax message = lg buffer / 32 (512 octets ici) */
typedef struct {
/* buffer servant de stack pour number et string */
number num; /* nombre si str == NULL */
@@ -187,64 +188,78 @@ typedef struct {
/* vrai buffer read = position a lire dans les donnees (a ajouter a ptr) ou prochaine position a ecrire (pile calcul et appel) */
/* vrai buffer write = position a ecrire dans les donnees (a ajouter a ptr) ; si READ=WRITE : vide ! ou utilise en interne si pile */
#define OID_MAX 9999999999999999ll /* pour que l'OID reste sur 16 chiffres : 16 neufs ici */
#define OID_MAX 999999999999999ll /* pour que l'OID reste sur 16 chiffres : 15 neufs ici, pour qu'un oid commence toujours par 0 ! */
#define OID_MIN 100ll /* demarrage a 100 pour eviter les nombres trop petits */
#define CLASS_BASE "Base" /* classe mere de toutes les classes */
#define MAX_PARAM 8 /* nb maxi de parametres d'une sub/methode */
enum {
BUF_LGMINBLOC = 16384, /* multiple de 32 sinon pile d'elements 8 et 16 octets KO, lgmax message = lg buffer / 32 (512 octets ici) */
MAX_PARAM = 8, /* nb maxi de parametres d'une sub/methode */
#define HASH_READ 1
#define HASH_DELETE 2
#define HASH_WRITE 3
HASH_READ = 1,
HASH_DELETE = 2,
HASH_WRITE = 3,
#define NOK -1 /* quand pas une exception */
NOK = -1 /* quand pas une exception */
};
//
// 000 a 999 : erreur systeme
// 1000 a 9999 : reserve aux modules systeme
// 1000 a 1099 : module "db"
//
#define OK 0
#define EX_DIV0 1 /* exceptions */
#define EX_MEM 2 /* memalloc ko */
#define EX_BUFOVF 3 /* depassement de capacite du buffer */
#define EX_IO 4 /* erreur d'entree/sortie (leture fichier...) */
#define EX_END 5 /* adresse du code hors prog/sub */
#define EX_LGNOM 6 /* lg nom variable incorrecte (de 1 a 24 inclus) */
#define EX_TYPVAR 7 /* type variable non attendu */
#define EX_NULLOCAL 8 /* hashtable locale null et pas dans le code "global" */
#define EX_NOVAR 9 /* nom de variable inconnu */
#define EX_MODOPEN 10 /* erreur ouverture module (dlopen) */
#define EX_MODDSYM 11 /* fonction execModule non trouvee dans le module (dsym) */
#define EX_NOSTACK 12 /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
#define EX_NAVAR 13 /* la variable n'est pas du bon type / not available */
#define EX_NOADVAR 14 /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
#define EX_NAVERS 15 /* version de pcode non prise en charge par le "compilateur" */
#define EX_MODNAME 16 /* le nom d'appel du module est incorrect */
#define EX_DYNERR 17 /* erreur dans la manipulation des chaines */
#define EX_MODFUNC 18 /* le code function du module est inconnu */
#define EX_MODPARAM 19 /* le parametre donne au module est incorrect */
#define EX_MODETAT 20 /* l'etat interne du module est incorrect */
#define EX_MODERR 21 /* erreur specifique au module */
#define EX_NOTNUM 22 /* erreur de conversion de chaine en number */
#define EX_NOCLASS 23 /* la classe n'a pas ete trouvee dans la hash globale */
#define EX_CMDLINE_ARG 24 /* erreur dans les parametres de la ligne de commande */
#define EX_PCODE 25 /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
#define EX_NOENVVAR 26 /* WBIN et/ou WSRC non defini en var d'environnement ou non passe en parametre de la ligne de commande */
#define EX_EXCEPTNUM 27 /* code except ne tient pas sur 8 bits : ko pour retour shell */
#define EX_BINVAR_KO 28 /* variable _bin de g non trouvee */
#define EX_ENVVAR_KO 29 /* variable _env de g non trouvee */
#define EX_BINADDRVAR_KO 30 /* variable _binaddr de g non trouvee */
#define EX_CREATEHASH 31 /* erreur de creation de hashtable (memoire) */
#define EX_FIELD_KO 32 /* erreur lors de dynField (memoire ou param incorrect) */
#define EX_SUBSTR_KO 33 /* erreur lors de dynSubstr (memoire ou param incorrect) */
#define EX_SEP_INCORRECT 34 /* separateurs incorrects dans setsep (0 interdit) */
#define EX_FORMAT_KO 35 /* erreur de parametre (type format ou longueur incorrects) */
#define EX_INSERT_KO 36 /* erreur de parametre ou memoire dans insert() */
#define EX_REMOVE_KO 37 /* erreur de parametre ou memoire dans remove() */
#define EXNB 37 /* MEMO !!!! */
enum {
OK = 0,
EX_DIV0 = 1, /* division par zero */
EX_MEM = 2, /* memalloc ko */
EX_BUFOVF = 3, /* depassement de capacite du buffer */
EX_IO = 4, /* erreur d'entree/sortie (lecture fichier...) */
EX_END = 5, /* adresse du code hors prog/sub */
EX_LGNOM = 6, /* lg nom variable incorrecte (de 1 a 24 inclus) */
EX_TYPVAR = 7, /* type variable non attendu */
EX_NULLOCAL = 8, /* hashtable locale null et pas dans le code "global" */
EX_NOVAR = 9, /* nom de variable inconnu */
EX_MODOPEN = 10, /* erreur ouverture module (dlopen) */
EX_MODDSYM = 11, /* fonction execModule non trouvee dans le module (dsym) */
EX_NOSTACK = 12, /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
EX_NAVAR = 13, /* la variable n'est pas du bon type / not available */
EX_NOADVAR = 14, /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
EX_NAVERS = 15, /* version de pcode non prise en charge par le "compilateur" */
EX_MODNAME = 16, /* le nom d'appel du module est incorrect */
EX_DYNERR = 17, /* erreur dans la manipulation des chaines */
EX_MODFUNC = 18, /* le code function du module est inconnu */
EX_MODPARAM = 19, /* le parametre donne au module est incorrect */
EX_MODETAT = 20, /* l'etat interne du module est incorrect */
EX_MODERR = 21, /* erreur specifique au module */
EX_NOTNUM = 22, /* erreur de conversion de chaine en number */
EX_NOCLASS = 23, /* la classe n'a pas ete trouvee dans la hash globale */
EX_CMDLINE_ARG = 24, /* erreur dans les parametres de la ligne de commande */
EX_PCODE = 25, /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
EX_NOENVVAR = 26, /* WBIN et/ou WSRC non defini en var d'environnement ou non passe en parametre de la ligne de commande */
EX_EXCEPTNUM = 27, /* code except ne tient pas sur 8 bits : ko pour retour shell */
EX_BINVAR_KO = 28, /* variable _bin de g non trouvee */
EX_ENVVAR_KO = 29, /* variable _env de g non trouvee */
EX_BINADDRVAR_KO = 30, /* variable _binaddr de g non trouvee */
EX_CREATEHASH = 31, /* erreur de creation de hashtable (memoire) */
EX_FIELD_KO = 32, /* erreur lors de dynField (memoire ou param incorrect) */
EX_SUBSTR_KO = 33, /* erreur lors de dynSubstr (memoire ou param incorrect) */
EX_SEP_INCORRECT = 34, /* separateurs incorrects dans setsep (0 interdit) */
EX_FORMAT_KO = 35, /* erreur de parametre (type format ou longueur incorrects) */
EX_INSERT_KO = 36, /* erreur de parametre ou memoire dans insert() */
EX_REMOVE_KO = 37, /* erreur de parametre ou memoire dans remove() */
EX_CHILD_FORK = 38, /* erreur de fork sur nouveau process */
EX_CHILD_EXEC = 39, /* erreur execution nouveau process */
EX_ZERO_FOR_INCR = 40, /* erreur increment a zero dans une boucle foreach numerique */
EX_SORTEDSEARCH_KO = 41, /* erreur de parametre (type de tri incorrect) */
EX_SQRT_NEG = 42, /* racine carre d'un nombre negatif non calculee */
EX_INT_EXP = 43, /* exponentiation fractionnaire non calculee */
EX_VARPARAM_KO = 44, /* la variable passee en parametre n'est plus presente en memoire */
EX_PARAM_NOTFOUND = 45, /* la variable passee en parametre est affectee a un nom de parametre inconnu de la sub */
EX_NUMOVF = 46, /* depassement de capacite lors d'un calcul */
EXNB = 46 /* 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 ! */
@@ -257,8 +272,6 @@ typedef struct {
octet tmp_cpt; /* nb de var tmp Dynamic, ne pas sauvegarder car dans la hash globale */
octet tmp_free; /* numero de var tmp Dynamic dispo ; si > tmp_cpt, a creer dans la hash globale */
//
//var tblptr; /* contient les pointeurs sur les vars de type SUB/PARAM/OBJET, pour les rendre VAR_NULL si le ptr est libere */
//
var tmp_dynamic; /* comme son nom l'indique... doit etre utilise localement et sur une portee tres courte ; pas d'utilisation inter instruction */
var int_number; /* variable number interne servant aux conversions */
var int_dynamic; /* variable dynamic interne servant aux conversions */
@@ -267,6 +280,9 @@ typedef struct {
var v; /* variable servant en interne */
var * ad_var; /* permet de recuperer l'adresse d'une var entre 2 instructions */
var * ad_var_hash; /* dans les enchainements PVAR/PVAH-PVAI, donne l'adresse de la hash possédant la "derniere" variable */
var * ad_var_obj; /* dans une affectation let ou do sub, donne l'objet concerne si objet, pour lire les membres (hors sub) -> pour creer this */
var * ad_var_class; /* donne l'objet de la classe mere de l'objet courant, objet Base si objet de classe Base */
var * ad_var_sav; /* pour memoriser ad_var sur une affectation simple let a.b = c.d, instruction SADV / VLET / PHDV / PIDV */
/* */
ent64 exception; /* exception courante (di) ; 0 ok, si # 0, levee d'une exception et saut au code qui le traite, 0 a chaque debut de fonction */
ent64 except_ex; /* dans bloc except, code erreur ayant genere l'exception ; a mettre a 0 a chaque debut de methode sauf si appel depuis le bloc except ! */
@@ -283,6 +299,8 @@ typedef struct {
var debugreglelex;
var debugcmd;
var debugvalex;
var printf;
void * debugCtxShm; /* pour le debug des process phantom */
/* */
octet bin_comp; /* indique si les binaires lus sont compresses (1) et si oui, avec une cle (2), 0 RAS */
octet demon; /* 1 si prog lance en demon, 0 sinon (lu par @demon) */
@@ -297,6 +315,9 @@ typedef struct {
char sep_field, sep_subfield; /* pour dynamic */
/* */
int endianess; /* pour detection automatique de l'endianess de la plateforme d'execution */
int use_signal; /* 1 si w gere et traite les signaux, 0 sinon (mode plugin : signaux geres par programme maitre) */
/* */
int level; /* niveau d'imvrication des appels do/call ; prog principal = level 1 */
/* */
int bin_indice; /* position dans _bin du binaire en cours d'exec ( _bin<2, bin_indice> ) */
/* */
@@ -305,42 +326,76 @@ typedef struct {
pointeur si_except; /* position dans le source du code traitant les exceptions (apres instruction EXC) */
/* */
pointeur binaddr; /* permet de lire les adresses binaires en mode Trace */
/* */
pointeur ctxLzw; /* pointeur sur le contexte lzw pour decompresser les binaires wp compresse */
/* */
ent64 mem_numb; /* nombre de blocs memoire alloues */
ent64 mem_size; /* taille des bloc memoire alloues */
/* */
ent64 oid_cpt; /* compteur pour les object ID (OID) */
/* */
char oidc[24]; /* conversion en ascii, mis en binaire (16 chiffres max car 2x8 octets), oid3 ne sert pas (0)
seuls les 15 premiers cars servent, les 8 derniers sont des fillers pour aller a 24 cars */
char oidc[24]; /* conversion en ascii, mis en binaire (16 chiffres max car 2x8 octets), oid3 ne sert pas (0)
seuls les 15 premiers cars servent, les 8 derniers sont des fillers pour aller a 24 cars */
/* */
union { /* var interne pour copie d'une cle d'acces a un element d'une hashtable */
ent64 nom64[3];
char nom[24];
};
int zero1; /* permet de gerer la chaine precedente nom en sz */
union {
ent64 fn64[3];
char fn[24]; // nom de la fonction appelee par un module (max 23 cars)
char fn[24]; /* nom de la fonction appelee par un module (max 23 cars) - A REVOIR avec le int zero qui suit !! */
};
int zero2; /* permet de gerer la chaine precedente nom en sz */
/* */
long (*pop)(struct env * e, var *); /* utilise pour lire les parametres nommes dans les modules C */
/* table des caracteres de '000' a '999' (pour conversion) */
char tbl_1000[3000];
/* */
char var_car[VAR_NB + 1]; /* lettre caracteristique de chaque type (printdebug) */
} env;
#define CMP_EQ 1
#define CMP_NE 2
#define CMP_LT 3
#define CMP_GT 4
#define CMP_LE 5
#define CMP_GE 6
enum {
CMP_EQ = 1,
CMP_NE = 2,
CMP_LT = 3,
CMP_GT = 4,
CMP_LE = 5,
CMP_GE = 6,
CMP_AND = 7,
CMP_OR = 8,
CMP_NOT = 9,
CMP_FOR = 10
};
#define CMP_AND 7
#define CMP_OR 8
#define CMP_NOT 9
enum {
FORMAT_TRIM = 1,
FORMAT_LEFT = 2,
FORMAT_RIGHT = 3,
FORMAT_CENTER = 4,
FORMAT_SURROUND = 5
};
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@forcount,@kill,@fork,@exceptstr,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@number,@dynamic,@empty,@trim,@left,@right,@center,@surround;1,2,3,4,5,6,7,8,10,11,12,13,14,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,40,41,42,50,51,52,53,54"
enum {
SORTEDSEARCH_NONE = 0,
SORTEDSEARCH_ASC = 1, // = DYN_SORT_ASC
SORTEDSEARCH_DESC = 2 // = DYN_SORT_DESC
};
#define GUV_CLASS "_class"
#define GUV_BINADDR "_binaddr"
#define GUV_LOCAL "_local"
#define GUV_ENV "_env"
#define GUV_ARG "_arg"
#define GUV_WARGV "_wargv"
#define GUV_ARGBACK "_argback"
#define GUV_SRCDBG "_srcdbg"
#define GUV_PROG "_prog"
#define GUV_STACK "_stack"
#define GUV_BIN "_bin"
#define GUV_WDIR "_wdir"
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@level,@kill,@oid,@prog,@exceptstr,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@cr,@lf,@tab,@number,@dynamic,@empty,@trim,@left,@right,@center,@surround,@asc,@desc;1,2,3,4,5,6,7,8,10,11,12,13,14,15,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,50,51,52,53,54,55,56"
#include "global.h"
+445 -65
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -30,86 +30,319 @@ Exemple :
2 series de cars en ET, "-" optionnel puis de 1 a 9 chiffres ou A B C D E F en OU
<1> = 0,1,2D ; 1,9,30-39:41:42:43:44:45:46 (separe par \n )
Ajout: gestion des etats. Permet d'activer une regle si l'etat courant est celui indique, et si la regle est ok, peut changer l'etat
nombre: etat1 > etat2 (1,10,0-9)
"nombre" ne sera testee que si l'etat en cours est 'etat1' ; si la regle "nombre" est verifiee, l'etat courant passa a 'etat2'
la gestion des etats est facultative, signifiant que sans rien c'est l'etat 0 qui est en cours/actif (= pas d'etat)
(la compilation remplace les noms des etats par leur indice d'apparition a l'envers, en commencant a 1)
Regles lex pour le format lex :
-------------------------------
blanc: (1,*,#20#09) ;1; 1,-1,20:09
nomregle: [1,1,a-z] [0,*,0-9a-z] (1,1,#3A) ;2; 1,1,61-7A;0,-1,30-39:61-7A;1,1,3A
debut: (1,1,#28) ;3; 1,1,28
fin: (1,1,#29) ;4; 1,1,29
occ: [1,9,0-9] (1,1,#2C) ;5; 1,9,30-39;1,1,2C
infini: (1,1,#2A) (1,1,#2C) ;6; 1,1,2A;1,1,2C
commentaire: (1,1,#3B) [0,*,#09-#7E] ;7; 1,1,3B;0,-1,09-7E
intervalle: (1,1,#2D) ;8; 1,1,2D
hexa: (1,1,#23) [2,2,0-9A-F] ;9; 1,1,23;2,2,30-39:41-46
car: (1,1,#21-#7E) ;10; 1,1,21-7E
reste: (1,1,#00-#FF) ;11; 1,1,00-FF
blanc: (1,*,#20#09) ;1; 1,-1,20:09
nomregle: [1,1,a-z] [0,*,0-9a-z] (1,1,#3A) ;2; 1,1,61-7A;0,-1,30-39:61-7A;1,1,3A
etat: (0,24,0-9a-zA-Z) (1,1,#3E) (0,24,0-9a-zA-Z) ;3; 0,24,30-39:61-7A:41-5A;1,1,3E;0,24,30-39:61-7A:41-5A
debut: (1,1,#28) ;4; 1,1,28
fin: (1,1,#29) ;5; 1,1,29
occ: [1,9,0-9] (1,1,#2C) ;6; 1,9,30-39;1,1,2C
infini: (1,1,#2A) (1,1,#2C) ;7; 1,1,2A;1,1,2C
commentaire: (1,1,#3B) [0,*,#09-#7E] ;8; 1,1,3B;0,-1,09-7E
intervalle: (1,1,#2D) ;9; 1,1,2D
hexa: (1,1,#23) [2,2,0-9A-F] ;10; 1,1,23;2,2,30-39:41-46
car: (1,1,#21-#7E) ;12; 1,1,21-7E
reste: (1,1,#00-#FF) ;12; 1,1,00-FF
[] est remplace par () car cela revient au meme !
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
static char cLF = 10;
/*
blanc,1,nomregle,2,etat,3,debut,4,fin,5,occ,6,infini,7,commentaire,8,intervalle,9,hexa,10
car,11,reste,12
*/
//static char * nr[] = {"blanc", "nomregle", "etat", "debut", "fin", "occ", "infini", "commentaire", "intervalle", "hexa", "car", "reste"};
static struct {
ent16 blanc, nomregle, etat, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} rlex;
/*static void debug_valex(env * e, Dynamic * valex, Dynamic * tmp, Dynamic * tmp2)
{
int nbval = dynDcount(e, valex, cVM, 2, cFM);
for(int v = 1; v <= nbval; v++)
{
ent64 tok = dynFieldAsNumber(e, valex, 2, v, cFM, cVM);
dynField(e, valex, tmp, 1, v, cFM, cVM, 1);
hex2str(e, tmp, tmp2);
printf("%s/%lld:%s ", nr[tok - 1], tok, tmp2->mPtr);
}
printf("\n");
}*/
WAPIDECL long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
/* renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique */
long pos = dynLocateSz(e, regles, nom, ',', 1, ';');
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, ';', ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
WAPIDECL void init_reg_lex(env * e, Dynamic * regles, Dynamic * tmp)
{
rlex.blanc = rg(e, regles, "blanc", tmp); // 1
rlex.nomregle = rg(e, regles, "nomregle", tmp); // 2
rlex.etat = rg(e, regles, "etat", tmp); // 3
rlex.debut = rg(e, regles, "debut", tmp); // 4
rlex.fin = rg(e, regles, "fin", tmp); // 5
rlex.occ = rg(e, regles, "occ", tmp); // 6
rlex.infini = rg(e, regles, "infini", tmp); // 7
rlex.commentaire = rg(e, regles, "commentaire", tmp); // 8
rlex.intervalle = rg(e, regles, "intervalle", tmp); // 9
rlex.hexa = rg(e, regles, "hexa", tmp); // 10
rlex.car = rg(e, regles, "car", tmp); // 11
rlex.reste = rg(e, regles, "reste", tmp); // 12
}
WAPIDECL long parse_lex(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours, int runtime)
{
#define nreg(x) ((x)*2 > trav->mLg ? 0 : *(ent16 *)(trav->mPtr + (x)*2 - 2))
/* */
static int numlig = 0;
numlig++;
/* */
if(valex->mLg == 0)
return OK; /* ligne vide */
/* */
int nbres = dynDcount(e, resultat, cLF, DYN_NONE, DYN_NONE);
int nbval = dynDcount(e, valex, cVM, 2, cFM);
ent16 regle;
dynSetLen(e, trav, 0);
dynSetLen(e, encours, 0);
for(int ival = nbval; ival > 0; ival--)
{
/* suppression des regles 1 et 7 (blanc et commentaire) */
dynField(e, valex, tmp, 2, ival, cFM, cVM, 1);
regle = dynToNum(e, tmp, DYN_FALSE, 0);
if(regle == rlex.blanc || regle == rlex.commentaire)
{
dynDel(e, valex, 1, ival, cFM, cVM, 1);
dynDel(e, valex, 2, ival, cFM, cVM, 1);
dynDel(e, valex, 3, ival, cFM, cVM, 1);
}
else
{
if(dynCtrl(e, trav, trav->mLg + 2, TRUE) != DYN_OK)
return DYN_ERR;
if(trav->mLg > 0)
memcopie(trav->mPtr + 2, trav->mPtr, trav->mLg);
*(ent16 *)(trav->mPtr) = regle;
dynSetLen(e, trav, trav->mLg + 2);
}
}
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
/*debug_valex(e, valex, tmp, encours);
dynSetLen(e, encours, 0);*/
/* */
ent16 n = 1, n_prem_et;
/* debut d'analyse des tokens : nomregle */
if(nreg(n) != rlex.nomregle)
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_RULENAME_EXPECTED;
}
n++;
if(nreg(n) == rlex.etat)
{
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
// encours: "etat1>etat2"
dynChange(e, encours, ">", ";", 1);
dynConcatSz(e, encours, ";", 1);
n++;
}
else
dynLet(e, encours, ";;", 1); /* equivalent a "pas d'etat" */
if(resultat->mLg == 0)
dynLet(e, resultat, "\n", 1);
dynStore(e, resultat, 1, nbres == 0 ? 2 : nbres * 2 , encours, cLF, ';');
/* liste de et/ou */
n_prem_et = n;
for(;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == rlex.debut || regle == rlex.car) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : car ou debut et/ou attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_CHAR_BRACKET_EXPECTED;
}
/* et */
if(n == n_prem_et)
dynStoreSz(e, valex, 4, DYN_NONE, "", 0, cFM, DYN_NONE);
else
dynConcatSz(e, valex, ";", 1);
/* */
if(regle == rlex.car)
{
/* 1 caractere = (1,1,car) (raccourci d'ecriture) */
dynConcatSz(e, valex, "1,1,", 4);
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(e, valex, tmp);
n++;
continue;
}
if(nreg(n+1) == rlex.occ && (nreg(n+2) == rlex.occ || nreg(n+2) == rlex.infini)) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : occurence min/max attendue %d\n", numlig, tmp->mPtr, n);
return EXMOD_COMPILE_OCCURENCE_EXPECTED;
}
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
dynConcat(e, valex, encours); // occmin
n++;
if(nreg(n) == rlex.infini)
dynConcatSz(e, valex, "-1,", 3);
else
{
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
dynConcat(e, valex, encours); // occmax
}
ent16 n1,n2,n3; char unefois[2] = {0};
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
/* TODO refactor conditions */
while(n1 == rlex.car || n1 == rlex.hexa || ((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa)))
{
dynConcatSz(e, valex, unefois, DYN_LGNONE);
if((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa))
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
if(n1 == rlex.car)
dynConcat(e, valex, tmp);
else
{
hex2str(e, tmp, encours);
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
dynConcatSz(e, valex, "-", 1);
n += 2;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
if(n3 == rlex.car)
dynConcat(e, valex, tmp);
else
{
hex2str(e, tmp, encours);
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
}
else if(n1 == rlex.car)
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(e, valex, tmp);
}
else if(n1 == rlex.hexa)
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
unefois[0] = ':';
}
if(unefois[0] == 0)
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : caractere/intervalle attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_CHAR_INTERVAL_EXPECTED;
}
if(n1 == rlex.fin) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : fin et/ou attendue\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_BRACKET_EXPECTED;
}
n += 2;
}
/* lecture nom regle en hexa */
dynField(e, valex, tmp, 1, 1, cFM, cVM, 1);
hex2str(e, tmp, trav);
trav->mPtr[trav->mLg - 1] = ','; /* exemple : begin,1,comment,2,... permet de faire un locate */
dynConcatSz(e, trav, Int64ToSz(e, nbres == 0 ? 1 : nbres, DYN_FALSE, 0), DYN_LGNONE);
dynStore(e, resultat, 1, nbres == 0 ? 1 : nbres * 2 - 1, trav, ';', ',');
/* */
dynField(e, valex, tmp, 4, DYN_NONE, cFM, DYN_NONE, 1);
nbres = (nbres == 0 ? 2 : nbres + 1);
dynStoreSz(e, resultat, nbres, DYN_NONE, tmp->mPtr, tmp->mLg, cLF, DYN_NONE);
/* */
#undef nreg
return OK;
}
#include "lex_files.h"
long regles_lex(env * e, Dynamic * r)
WAPIDECL long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
dynLet(e, r, "", 0);
dynConcatSz(e, r, "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11\n", DYN_LGNONE);
dynConcatSz(e, r, "1,-1,20:09\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,28\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,29\n", DYN_LGNONE);
dynConcatSz(e, r, "1,9,30-39;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2A;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,3B;0,-1,09-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2D\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,23;2,2,30-39:41-46\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,21-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,00-FF", DYN_LGNONE);
return DYN_OK;
}
//
long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
long cr;
long cr = DYN_ERR;
if(fichier_lex != NULL)
{
/* selon fichier_lex, lire directement depuis le source */
if(strncmp(fichier_lex, "debuglex", 8) == 0)
{
if(*file_debuglex == 0)
#ifdef WINLIB
cr = dynRead(e, regles, "C:\\Users\\Poupougne42\\source\\repos\\win_w_src\\lex\\debuglex"); // lire les regles depuis le fichier sur disque
#else
cr = dynRead(e, regles, "/etc/wlanguage/debuglex"); // lire les regles depuis le fichier sur disque
#endif
else
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "wlex", 4) == 0)
{
if(*file_wlex == 0)
#ifdef WINLIB
cr = dynRead(e, regles, "C:\\Users\\Poupougne42\\source\\repos\\win_w_src\\lex\\wlex"); // lire les regles depuis le fichier sur disque
#else
cr = dynRead(e, regles, "/etc/wlanguage/wlex"); // lire les regles depuis le fichier sur disque
#endif
else
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "lexlex", 6) == 0)
{
cr = dynLet(e, regles, file_lexlex, DYN_LGNONE);
}
else
cr = dynRead(e, regles, fichier_lex); // lire les regles depuis le fichier sur disque
}
else
cr = regles_lex(e, regles); // par defaut, charger les regles lex des fichiers "lex" (?!)
//
if(cr == DYN_OK)
{
dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
//dynDel(e, regles, 1, DYN_NONE, 10, DYN_NONE, 1); /* la premiere ligne contient le <numero,nom> des regles, separe par "," */
}
//dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
return cr;
}
//
long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
static long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
{
long conc = 1, lgconc = 0, fin = FALSE, ichaine = 0, nch, t1, t2, trouve;
long occmin, occmax, occtrouve, occsuiv;
@@ -208,18 +441,20 @@ long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dyna
conc = lgconc;
return conc;
}
//
void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
WAPIDECL void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
{
/* vars Dynamic :
regles (en entree) : liste des regles ; etregle : regle ET en cours
elem detail : partie de la regle ET en cours
trouvemot, residu, motencours : utilise par la fonction de decodage en token lex()
valex (en sortie) : chaine/noregle/position ; saisie (en entree) : chaine a decoder */
Dynamic etregle, residu, motencours, trouvemot, elem, detail;
Dynamic etregle, residu, motencours, trouvemot, elem, detail, tabetat;
long eof = 0, trouveregle = 0, encours = 0, posaisie = 0, nbvalex = 0, iregle = 0;
long concorde = 0, postoken = 1; // position dans la chaine en entree de chaque token trouve
char car[3] = {0}, hexa[16] = {"0123456789ABCDEF"};
long nbetat;
short etat = *(short *)"0\0"; // etat en cours, par defaut 0 = pas d'etat (2 octets)
//
if(e == NULL || saisie == NULL || valex == NULL)
return;
@@ -234,6 +469,13 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynInit(e, &motencours, 0);
dynInit(e, &trouvemot, 0);
//
dynInit(e, &tabetat, 0);
dynRemove(e, regles, NULL, 0, DYN_TRUE);
dynRemove(e, regles, &tabetat, cLF, DYN_FALSE);
nbetat = dynDcount(e, &tabetat, ';', DYN_NONE, DYN_NONE); // securite
char ** petat = dynToTabPtr(e, &tabetat, ';');
/* maxi 99 etats sinon ko (car test sur 'short', 2 octets, pour les perfs) */
//
for(;;)
{
if(residu.mLg == 0)
@@ -281,6 +523,9 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynInsSz(e, valex, 2, nbvalex, Int64ToSz(e, trouveregle, FALSE, 0), DYN_LGNONE, cFM, cVM);
dynInsSz(e, valex, 3, nbvalex, Int64ToSz(e, postoken, FALSE, 0), DYN_LGNONE, cFM, cVM);
//
if(trouveregle * 2 < nbetat) // securite
etat = *(short *)petat[trouveregle * 2]; // nouvel etat courant suite a acceptation de la regle
//
if(motencours.mLg > trouvemot.mLg)
dynConcatSz(e, &residu, motencours.mPtr + trouvemot.mLg, motencours.mLg - trouvemot.mLg);
postoken += trouvemot.mLg/2;
@@ -300,10 +545,15 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynConcatSz(e, &motencours, car, 2);
iregle = 0;
dynRemove(e, regles, NULL, 0, DYN_TRUE);
dynRemove(e, regles, &etregle, 10, DYN_FALSE); /* ignorer la premiere ligne car contient le <numero,nom> des regles, separe par "," */
while(dynRemove(e, regles, &etregle, 10, DYN_FALSE) > -1)
dynRemove(e, regles, &etregle, cLF, DYN_FALSE); /* ignorer la premiere ligne car contient le <numero,nom> des regles, separe par "," + etats */
while(dynRemove(e, regles, &etregle, cLF, DYN_FALSE) > -1)
{
iregle++;
// gerer etat ici, pas dans "concorde_h"
if(iregle * 2 - 1 < nbetat)
if(etat != *(short *)petat[iregle * 2 - 1])
continue; // etat_pre incomptible : passer a la regle suivante
//
//
concorde = concorde_h(e, &motencours, &etregle, &elem, &detail);
//
@@ -341,6 +591,9 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynInsSz(e, valex, 2, nbvalex, Int64ToSz(e, trouveregle, FALSE, 0), DYN_LGNONE, cFM, cVM);
dynInsSz(e, valex, 3, nbvalex, Int64ToSz(e, postoken, FALSE, 0), DYN_LGNONE, cFM, cVM);
//
if(trouveregle * 2 < nbetat) // securite
etat = *(short *)petat[trouveregle * 2]; // nouvel etat courant suite a acceptation de la regle
//
if(motencours.mLg > trouvemot.mLg)
dynConcatSz(e, &residu, motencours.mPtr + trouvemot.mLg, motencours.mLg - trouvemot.mLg);
postoken += trouvemot.mLg/2;
@@ -360,7 +613,134 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynFree(e, &residu);
dynFree(e, &motencours);
dynFree(e, &trouvemot);
dynFree(e, &tabetat);
}
WAPIDECL long compile_maj_etat(env * e, Dynamic * resultat, Dynamic * res1, Dynamic * liste_etat, Dynamic * etat)
{
// resultat<1> (LF) => regle1,1,regle2,2,regle3,3;etatpre1;etatpost1;etatpre2;etatpost1;;etatpost2
dynField(e, resultat, res1, 1, DYN_NONE, cLF, DYN_NONE, 1);
// remplacer chaque etat par son indice (ordre d'apparition), 0 si vide
long nbe = 0, cptr, nbr = dynDcount(e, res1, ';', DYN_NONE, DYN_NONE);
dynSetLen(e, liste_etat, 0); // liste des etats, sans doublon
for(cptr = 2; cptr <= nbr; cptr++)
{
dynField(e, res1, etat, cptr, DYN_NONE, ';', DYN_NONE, 1);
if(etat->mLg == 0)
dynStoreSz(e, res1, cptr, DYN_NONE, "0", 1, ';', DYN_NONE);
else
{
long pos = dynLocateSz(e, liste_etat, etat->mPtr, ';', DYN_NONE, DYN_NONE);
if(pos == 0)
{
pos = (++nbe);
dynStore(e, liste_etat, pos, DYN_NONE, etat, ';', DYN_NONE);
if(nbe > 99)
return EXMOD_COMPILE_STATECOUNT_TOOBIG;
}
dynStoreSz(e, res1, cptr, DYN_NONE, Int64ToSz(e, pos, FALSE, 0), DYN_LGNONE, ';', DYN_NONE);
}
}
dynStore(e, resultat, 1, DYN_NONE, res1, cLF, DYN_NONE);
return OK;
}
WAPIDECL long compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile)
{
// "compile" les regles lex fournies dans <fichier_lex> et renvoi le resultat dans <compile>
// <1> = nom et numeros des regles, <2> a <n> = regles lex
long cr = DYN_OK, ret = 0;
Dynamic regles, tmp, ligne, tmp1, tmp2, tmp3;
//
dynInit(e, &regles, 0);
dynInit(e, &tmp, 0);
dynInit(e, &ligne, 0);
dynInit(e, &tmp1, 0);
dynInit(e, &tmp2, 0);
dynInit(e, &tmp3, 0);
//
dynSetLen(e, compile, 0);
//
cr = lire_regles_lex(e, &regles, "lexlex"); // <regles> = regles lex compiles
if(cr == DYN_OK)
{
init_reg_lex(e, &regles, &tmp);
dynErase(e, fichier_lex, "\r");
dynRemove(e, fichier_lex, NULL, 0, DYN_TRUE);
while(dynRemove(e, fichier_lex, &ligne, cLF, DYN_FALSE) > -1 && ret == 0)
{
lex(e, &regles, &ligne, &tmp); // tmp au format "valex" : chaine/noregle/position
ret = parse_lex(e, &tmp, compile, &tmp1, &tmp2, &tmp3, 1); /* 1 = runtime on (appel depuis lexMod), pas de printf */
}
if(ret == OK)
ret = compile_maj_etat(e, compile, &tmp, &tmp1, &tmp2);
cr = ret;
}
//
dynFree(e, &regles);
dynFree(e, &tmp);
dynFree(e, &ligne);
dynFree(e, &tmp1);
dynFree(e, &tmp2);
dynFree(e, &tmp3);
//
return cr;
}
WAPIDECL long compile_like(env * e, Dynamic * like, Dynamic * compile)
{
/* compile la chaine donnee par "like" (foreach dynamic/hashtable) ; regles =>
'*' a remplacer par [0,*,0-9a-zA-Z] => 0,-1,30-39:61-7A:41-5A
'+' a remplacer par [1,*,0-9a-zA-Z] => 1,-1,30-39:61-7A:41-5A
'?' : remplace une lettre [1,1,0-9a-zA-Z] => 1,1,30-39:61-7A:41-5A
'X' : chaque lettre/chiffre par [1,1,58] => 1,1,58
les autres caracteres sont ignores (si Dynamic, autoriser les autres ??)
concatener avec des ';' => like,1,other,2;0;0;0;0\n0,-1,30-39:61-7A:41-5A;2,2,58;0,-1,30-39:61-7A:41-5A\n1,1,00-FF pour l'exemple
*/
dynSetLen(e, compile, 0);
/* */
octet c;
long i, n = 0;
for(i = 0; i < like->mLg; i++)
{
c = like->ptr[i];
if(c == '*')
dynStoreSz(e, compile, ++n, DYN_NONE, "0,-1,30-39:61-7A:41-5A", 22, ';', DYN_NONE);
else if(c == '+')
dynStoreSz(e, compile, ++n, DYN_NONE, "1,-1,30-39:61-7A:41-5A", 22, ';', DYN_NONE);
else if(c == '?')
dynStoreSz(e, compile, ++n, DYN_NONE, "1,1,30-39:61-7A:41-5A", 21, ';', DYN_NONE);
else if((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z'))
{
dynStoreSz(e, compile, ++n, DYN_NONE, "1,1,", 21, ';', DYN_NONE);
dynConcatSz(e, compile, dynConvertCharToCharHexa(c), 2);
}
}
if(compile->mLg == 0)
{
/* cas particulier */
return DYN_ERR;
}
else
{
/* ajout necessaire au compile lex */
dynInsSz(e, compile, 1, DYN_NONE, "like,1,other,2;0;0;0;0", 22, cLF, DYN_NONE);
dynConcatSz(e, compile, "\n1,1,00-FF", cLF);
return DYN_OK;
}
}
/*
pour utiliser lex :
- compiler les regles 1 fois : compile_lex(e, regles, compile)
- analyser du contenu : lex(e, compile, contenu, valex)
le resultat est dans valex : <1> chaine hexa en VM, <2> no regle en VM, <3> position origine contenu en VM
le nom de la regle <no regle> se trouve comme cela : dynField(e, compile, nom, 1, noregle*2-1, 10, ',', 1)
la conversion en clair de la chaine hexa trouvee : hex2str(e, hexa, clair);
*/
/* source OK :
* LEX.REGLE = regles Lex, valeurs ET separees par "," ; liste de cars en OU pour chaque partie ET
LEX.REGLE = ""
+49
View File
@@ -0,0 +1,49 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifndef LEX_H
#define LEX_H
#define EXMOD_COMPILE_RULENAME_EXPECTED 1
#define EXMOD_COMPILE_CHAR_BRACKET_EXPECTED 2
#define EXMOD_COMPILE_OCCURENCE_EXPECTED 3
#define EXMOD_COMPILE_CHAR_INTERVAL_EXPECTED 4
#define EXMOD_COMPILE_BRACKET_EXPECTED 5
#define EXMOD_COMPILE_STATECOUNT_TOOBIG 6
#include "apidecl.h"
/* utilise par genlex */
WAPIDECL void init_reg_lex(env * e, Dynamic * regles, Dynamic * tmp);
WAPIDECL long parse_lex(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours, int runtime);
/* */
WAPIDECL long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex);
WAPIDECL void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex);
WAPIDECL long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp);
WAPIDECL long compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile);
WAPIDECL long compile_maj_etat(env * e, Dynamic * resultat, Dynamic * res1, Dynamic * liste_etat, Dynamic * etat);
WAPIDECL long compile_like(env * e, Dynamic * like, Dynamic * compile);
#endif
+256
View File
@@ -0,0 +1,256 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
#include "var.h"
#include "hashtable.h"
#include "convert.h"
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
/* codes erreur dans dans lex.h */
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Rule name expected",
"Bracket character expected",
"Number of occurence expected",
"Character interval expected",
"Bracket expected", // 5
"State count too big"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "compile", 7))
{
/* get param in the right order */
var * paramLexRules = getParam(e, "lexRules", 8);
var * paramCompiledRules = getParam(e, "compiledRules", 13);
var * paramRulesNameSet = getParam(e, "rulesNameSet", 12);
if(paramLexRules == NULL || paramCompiledRules == NULL)
exc = EX_MODPARAM;
else if(paramLexRules->type != VAR_DYNAMIC || paramCompiledRules->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, compile_lex(e, paramLexRules, paramCompiledRules));
if(exc == OK && paramRulesNameSet != NULL)
{
if(paramRulesNameSet->type != VAR_HASHTABLE)
var_let(e, paramRulesNameSet, &e->int_hash, FALSE, FALSE);
var * v = &e->int_number;
hashtable_clear(e, paramRulesNameSet);
long cpt, nb = dynDcount(e, paramCompiledRules, ',', 1, 10);
for(cpt = 1; cpt < nb;)
{
dynField(e, paramCompiledRules, &e->tmp_dynamic, 1, cpt++, 10, ',', 1);
e->int_number.num = dynFieldAsNumber(e, paramCompiledRules, 1, cpt++, 10, ',') * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, paramRulesNameSet, copy_nom(e, e->tmp_dynamic.mPtr), &v);
}
}
}
}
else if(modFnIs(e, "analyze", 7))
{
/* get param in the right order */
var * paramCompiledRules = getParam(e, "compiledRules", 13);
var * paramValue = getParam(e, "value", 5);
var * paramTokenList = getParam(e, "tokenList", 9);
if(paramCompiledRules == NULL || paramValue == NULL || paramTokenList == NULL)
exc = EX_MODPARAM;
else if(paramCompiledRules->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(paramTokenList->type != VAR_DYNAMIC)
var_let(e, paramTokenList, &e->int_dynamic, FALSE, FALSE);
lex(e, paramCompiledRules, paramValue, paramTokenList);
}
}
else if(modFnIs(e, "getToken", 8))
{
/* get param in the right order */
var * paramTokenList = getParam(e, "tokenList", 9);
var * paramTokenIndex = getParam(e, "tokenIndex", 10);
var * paramTokenSet = getParam(e, "tokenSet", 8);
if(paramTokenList == NULL || paramTokenIndex == NULL || paramTokenSet == NULL)
exc = EX_MODPARAM;
else if(paramTokenList->type != VAR_DYNAMIC || (paramTokenIndex->type != VAR_NUMBER && paramTokenIndex->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
/* ne pas vider la hash, juste ecrire 3 elements : ruleValue, ruleNumber, ruleLocation */
number indice;
if( ! var_conv_num(e, paramTokenIndex, &indice))
exc = EX_MODPARAM;
else
{
if(paramTokenSet->type != VAR_HASHTABLE)
{
var_let(e, paramTokenSet, &e->int_hash, FALSE, FALSE);
hashtable_clear(e, paramTokenSet);
}
indice /= NUM_FACTEUR;
var * n = &e->int_number;
n->num = dynExtractSubFieldAsNumber(e, paramTokenList, 2, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenNumber"), &n);
/* */
var * v = &e->int_dynamic, * w = &e->tmp_dynamic;
if(n->num == 0)
dynSetLen(e, v, 0);
else
{
dynExtractSubField(e, paramTokenList, 1, indice, w);
hex2str(e, w, v);
}
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenValue"), &v);
/* */
if(n->num != 0)
n->num = dynExtractSubFieldAsNumber(e, paramTokenList, 3, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, paramTokenSet, copy_nom(e, "tokenLocation"), &n);
}
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+162 -4
View File
@@ -1,6 +1,164 @@
//static char file_debuglex[] = "";
static char file_debuglex[] = "blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,reste,8\n1,-1,20:09:0A:0D\n1,2,61-7A:41-5A\n1,1,3F\n1,9,30-39\n1,1,2B\n1,1,2D\n1,1,3A;1,1,61-7A:41-5A:5F;0,23,61-7A:41-5A:30-39\n1,1,00-FF";
// !! ne pas mettre de caracteres \r dans les constantes ci-dessous !!
//static char file_wlex[] = "";
static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,free,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60,format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70,lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80,indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90,multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99\n1,-1,20:09\n1,1,3B;0,-1,00-FF\n1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n1,1,65;1,1,6E;1,1,64\n1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n1,1,73;1,1,75;1,1,62\n1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n1,1,69;1,1,66\n1,1,74;1,1,68;1,1,65;1,1,6E\n1,1,65;1,1,6C;1,1,73;1,1,65\n1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n1,1,64;1,1,6F\n1,1,63;1,1,61;1,1,6C;1,1,6C\n1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n1,1,69;1,1,6E\n1,1,6C;1,1,69;1,1,6B;1,1,65\n1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n1,1,6E;1,1,6F;1,1,70\n1,1,70;1,1,61;1,1,72;1,1,74\n1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n1,1,65;1,1,63;1,1,68;1,1,6F\n1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n1,1,6C;1,1,65;1,1,74\n1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n1,1,6E;1,1,65;1,1,77\n1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n1,1,74;1,1,68;1,1,69;1,1,73\n1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,65;1,1,65\n1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n1,1,69;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,61;1,1,63\n1,1,61;1,1,62;1,1,73\n1,1,6E;1,1,65;1,1,67\n1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,74;1,1,79;1,1,70;1,1,65\n1,1,6C;1,1,65;1,1,6E\n1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n1,1,3D\n1,1,23\n1,1,3E\n1,1,3C\n1,1,3E;1,1,3D\n1,1,3C;1,1,3D\n1,1,61;1,1,6E;1,1,64\n1,1,6F;1,1,72\n1,1,6E;1,1,6F;1,1,74\n1,1,28\n1,1,29\n1,1,7B\n1,1,7D\n1,1,5B\n1,1,5D\n1,1,21\n1,1,3F\n1,1,22;0,765,20-21:23-EF;1,1,22\n1,1,27;0,765,20-26:28-EF;1,1,27\n1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,40;1,-1,61-7A\n1,13,30-39;1,1,2E;0,5,30-39\n1,13,30-39\n1,1,2D\n1,1,2B\n1,1,2A\n1,1,2F\n1,1,5C\n1,1,25\n1,1,3A\n1,1,2C\n1,1,2E\n1,1,26\n1,1,00-FF";
// fichiers lex
/*static char file_lexlex[] = "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n"
"1,-1,20:09\n"
"1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n"
"1,1,28\n"
"1,1,29\n"
"1,9,30-39;1,1,2C\n"
"1,1,2A;1,1,2C\n"
"1,1,3B;0,-1,09-7E\n"
"1,1,2D\n"
"1,1,23;2,2,30-39:41-46\n"
"1,1,21-7E\n"
"1,1,00-FF";*/
static char file_lexlex[] = "blanc,1,nomregle,2,etat,3,debut,4,fin,5,occ,6,infini,7,commentaire,8,intervalle,9,hexa,10,car,11,reste,12;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n"
"1,-1,20:09\n"
"1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n"
"0,24,41-5A;1,1,3E;0,24,41-5A\n"
"1,1,28\n"
"1,1,29\n"
"1,9,30-39;1,1,2C\n"
"1,1,2A;1,1,2C\n"
"1,1,3B;0,-1,20-7E\n"
"1,1,2D\n"
"1,1,23;2,2,30-39:41-46\n"
"1,1,21-7E\n"
"1,1,00-FF";
// debugger w
static char file_debuglex[] = "blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,identnext,8,reste,9;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n"
"1,-1,20:09:0A:0D\n"
"1,2,61-7A:41-5A\n"
"1,1,3F\n"
"1,9,30-39\n"
"1,1,2B\n"
"1,1,2D\n"
"1,1,3A;1,1,61-7A:41-5A:5F;0,23,61-7A:41-5A:30-39\n"
"1,1,2E;1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n"
"1,1,00-FF";
// langage W
/*static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,"
"continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,sortedsearch,60,"
"change,61,format,62,insert,63,remove,64,tonum,65,tostring,66,equal,67,diff,68,gt,69,lt,70,gte,71,lte,72,and,73,or,74,not,75,beginpar,76,endpar,77,beginh,78,endh,79,begins,80,ends,81,indirect,82,typeof,83,stringdq,84,stringq,85,ident,86,varsys,87,numberdec,88,numberint,89,minus,90,"
"plus,91,multiply,92,divide,93,divident,94,modulo,95,concat,96,listesep,97,identsep,98,modsep,99,other,100"
"\n1,-1,20:09\n1,1,3B;0,-1,00-FF\n1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n1,1,65;1,1,6E;1,1,64\n1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n"
"1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n1,1,73;1,1,75;1,1,62\n1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n1,1,69;1,1,66\n1,1,74;1,1,68;1,1,65;1,1,6E\n1,1,65;1,1,6C;1,1,73;1,1,65\n1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n"
"1,1,64;1,1,6F\n1,1,63;1,1,61;1,1,6C;1,1,6C\n1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n"
"1,1,69;1,1,6E\n1,1,6C;1,1,69;1,1,6B;1,1,65\n1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n"
"1,1,6E;1,1,6F;1,1,70\n1,1,70;1,1,61;1,1,72;1,1,74\n1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n1,1,65;1,1,63;1,1,68;1,1,6F\n1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n1,1,6C;1,1,65;1,1,74\n1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n1,1,6E;1,1,65;1,1,77\n1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n"
"1,1,74;1,1,68;1,1,69;1,1,73\n1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n1,1,68;1,1,6F;1,1,6C;1,1,64\n1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n1,1,69;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,61;1,1,63\n1,1,61;1,1,62;1,1,73\n1,1,6E;1,1,65;1,1,67\n1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,74;1,1,79;1,1,70;1,1,65\n1,1,6C;1,1,65;1,1,6E\n1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n1,1,3D\n1,1,23\n1,1,3E\n1,1,3C\n1,1,3E;1,1,3D\n1,1,3C;1,1,3D\n"
"1,1,61;1,1,6E;1,1,64\n1,1,6F;1,1,72\n1,1,6E;1,1,6F;1,1,74\n1,1,28\n1,1,29\n1,1,7B\n1,1,7D\n1,1,5B\n1,1,5D\n1,1,21\n1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n1,1,22;0,765,20-21:23-EF;1,1,22\n1,1,27;0,765,20-26:28-EF;1,1,27\n1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,40;1,-1,61-7A\n1,13,30-39;1,1,2E;0,5,30-39\n1,13,30-39\n1,1,2D\n"
"1,1,2B\n1,1,2A\n1,1,2F\n1,1,5C\n1,1,25\n1,1,3A\n1,1,2C\n1,1,2E\n1,1,26\n1,1,00-FF";
*/
//static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102\n1,-1,20:09\n1,1,3B;0,-1,00-FF\n1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n1,1,65;1,1,6E;1,1,64\n1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n1,1,73;1,1,75;1,1,62\n1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n1,1,69;1,1,66\n1,1,74;1,1,68;1,1,65;1,1,6E\n1,1,65;1,1,6C;1,1,73;1,1,65\n1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n1,1,64;1,1,6F\n1,1,63;1,1,61;1,1,6C;1,1,6C\n1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n1,1,69;1,1,6E\n1,1,6C;1,1,69;1,1,6B;1,1,65\n1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n1,1,6E;1,1,6F;1,1,70\n1,1,70;1,1,61;1,1,72;1,1,74\n1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n1,1,65;1,1,63;1,1,68;1,1,6F\n1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n1,1,6C;1,1,65;1,1,74\n1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n1,1,6E;1,1,65;1,1,77\n1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n1,1,74;1,1,68;1,1,69;1,1,73\n1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n1,1,68;1,1,6F;1,1,6C;1,1,64\n1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n1,1,69;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,61;1,1,63\n1,1,61;1,1,62;1,1,73\n1,1,6E;1,1,65;1,1,67\n1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,73;1,1,71;1,1,72;1,1,74\n1,1,65;1,1,78;1,1,70\n1,1,74;1,1,79;1,1,70;1,1,65\n1,1,6C;1,1,65;1,1,6E\n1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n1,1,3D\n1,1,23\n1,1,3E\n1,1,3C\n1,1,3E;1,1,3D\n1,1,3C;1,1,3D\n1,1,61;1,1,6E;1,1,64\n1,1,6F;1,1,72\n1,1,6E;1,1,6F;1,1,74\n1,1,28\n1,1,29\n1,1,7B\n1,1,7D\n1,1,5B\n1,1,5D\n1,1,21\n1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n1,1,22;0,765,20-21:23-EF;1,1,22\n1,1,27;0,765,20-26:28-EF;1,1,27\n1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,40;1,-1,61-7A\n1,13,30-39;1,1,2E;0,5,30-39\n1,13,30-39\n1,1,2D\n1,1,2B\n1,1,2A\n1,1,2F\n1,1,5C\n1,1,25\n1,1,3A\n1,1,2C\n1,1,2E\n1,1,26\n1,1,00-FF";
static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0\n"
"1,-1,20:09\n"
"1,1,3B;0,-1,00-FF\n"
"1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n"
"1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n"
"1,1,65;1,1,6E;1,1,64\n"
"1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n"
"1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n"
"1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n"
"1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n"
"1,1,73;1,1,75;1,1,62\n"
"1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n"
"1,1,69;1,1,66\n"
"1,1,74;1,1,68;1,1,65;1,1,6E\n"
"1,1,65;1,1,6C;1,1,73;1,1,65\n"
"1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n"
"1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n"
"1,1,64;1,1,6F\n"
"1,1,63;1,1,61;1,1,6C;1,1,6C\n"
"1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n"
"1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n"
"1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n"
"1,1,6C;1,1,6F;1,1,6F;1,1,70\n"
"1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n"
"1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n"
"1,1,69;1,1,6E\n"
"1,1,6C;1,1,69;1,1,6B;1,1,65\n"
"1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n"
"1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n"
"1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n"
"1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n"
"1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n"
"1,1,6E;1,1,6F;1,1,70\n"
"1,1,70;1,1,61;1,1,72;1,1,74\n"
"1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n"
"1,1,65;1,1,63;1,1,68;1,1,6F\n"
"1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n"
"1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n"
"1,1,6C;1,1,65;1,1,74\n"
"1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n"
"1,1,6E;1,1,65;1,1,77\n"
"1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n"
"1,1,74;1,1,68;1,1,69;1,1,73\n"
"1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n"
"1,1,68;1,1,6F;1,1,6C;1,1,64\n"
"1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n"
"1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n"
"1,1,69;1,1,6E;1,1,74\n"
"1,1,66;1,1,72;1,1,61;1,1,63\n"
"1,1,61;1,1,62;1,1,73\n"
"1,1,6E;1,1,65;1,1,67\n"
"1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,73;1,1,71;1,1,72;1,1,74\n"
"1,1,65;1,1,78;1,1,70\n"
"1,1,74;1,1,79;1,1,70;1,1,65\n"
"1,1,6C;1,1,65;1,1,6E\n"
"1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n"
"1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n"
"1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n"
"1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n"
"1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n"
"1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n"
"1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n"
"1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n"
"1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n"
"1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n"
"1,1,3D\n"
"1,1,23\n"
"1,1,3E\n"
"1,1,3C\n"
"1,1,3E;1,1,3D\n"
"1,1,3C;1,1,3D\n"
"1,1,61;1,1,6E;1,1,64\n"
"1,1,6F;1,1,72\n"
"1,1,6E;1,1,6F;1,1,74\n"
"1,1,28\n"
"1,1,29\n"
"1,1,7B\n"
"1,1,7D\n"
"1,1,5B\n"
"1,1,5D\n"
"1,1,21\n"
"1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n"
"1,1,22;0,765,20-21:23-EF;1,1,22\n"
"1,1,27;0,765,20-26:28-EF;1,1,27\n"
"1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n"
"1,1,40;1,-1,61-7A\n"
"1,13,30-39;1,1,2E;0,5,30-39\n"
"1,13,30-39\n"
"1,1,2D\n"
"1,1,2B\n"
"1,1,2A\n"
"1,1,2F\n"
"1,1,5C\n"
"1,1,25\n"
"1,1,3A\n"
"1,1,2C\n"
"1,1,2E\n"
"1,1,26\n"
"1,1,00-FF";
+31 -6
View File
@@ -1,3 +1,25 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
@@ -7,8 +29,10 @@
tester avec alloc (size 20) !! TODO
*/
#define MAX_ENTRY 3838 // 4096 - 258
#define SIZE_ENTRY (124 + sizeof(int)) // TODO : voir la meilleure taille 91 sur fichier binaire de 130 Ko... !!! tester avec 20...
enum {
MAX_ENTRY = 3838, // 4096 - 258
SIZE_ENTRY = (124 + sizeof(int)) // TODO : voir la meilleure taille 91 sur fichier binaire de 130 Ko... !!! tester avec 20...
};
typedef struct {
octet Dict[MAX_ENTRY * SIZE_ENTRY]; // dictionnaire en cours
@@ -20,11 +44,12 @@ typedef struct {
long prec; // dernier code trouve dans le dict
long bits; // nb de bits en cours (codage/decodage)
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal)
int inverse; // "inverse" le decodage des bits LZW (cas des fichiers GIF)
} modContextLzw;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void initLzw(env * e, modContextLzw * cl);
void freeLzw(env * e, modContextLzw * cl);
long setLzw(env * e, var * clair, modContextLzw * cl, int type);
long getLzw(env * e, var * comp, modContextLzw * cl, int type);
WAPIDECL void initLzw(env * e, modContextLzw * cl);
WAPIDECL void freeLzw(env * e, modContextLzw * cl);
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type);
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type);
+115 -102
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,157 +27,170 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "lzw.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextLzw cl;
/*var dict; // de type dynamic, dictionnaire en cours
var code; // de type dynamic, contient le code/decode en cours
var w; // de type dynamic, contient la chaine en cours d'analyse
long prec; // dernier code trouve dans le dict
long posDict;// position en cours du code dans dict + 256 (dernier)
long bits; // nb de bits en cours (codage/decodage)
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal) */
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
//long set(env * e, var * clair, modEtat * pe, int type);
//long get(env * e, var * code, modEtat * pe, int type);
//long setV2(env * e, var * clair, modEtat * pe, int type);
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initLzw(e, &p_etat->cl);
//dynInit(e, &p_etat->dict, 4096);
//dynInit(e, &p_etat->code, 4096);
//dynInit(e, &p_etat->w, 256);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initLzw(e, &p_etat->cl);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeLzw(e, &p_etat->cl);
//dynFree(e, &p_etat->dict);
//dynFree(e, &p_etat->code);
//dynFree(e, &p_etat->w);
//*** FIN du code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(p_etat == NULL)
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
exc = EX_MODETAT;
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "set", 3))
{
/* compression du clair de param, en une fois */
/* sinon utiliser : setinit, setnext, setend */
/*exc = setError(p_etat, EXMOD_xxx);*/
if(p_etat == NULL)
exc = EX_MODETAT;
/* get param in the right order */
var * paramPlaintextThenCompressed = getParam(e, "plaintextThenCompressed", 23);
if(paramPlaintextThenCompressed == NULL)
exc = EX_MODPARAM;
else if(paramPlaintextThenCompressed->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, setLzw(e, paramPlaintextThenCompressed, &p_etat->cl, 0)); /* compression compatible PDF (mais pas GIF), 0 : en une fois */
}
else if(modFnIs(e, "get", 3))
{
/* get param in the right order */
var * paramCompressedThenPlaintext = getParam(e, "compressedThenPlaintext", 23);
var * paramReverse = getParam(e, "reverse", 7);
if(paramCompressedThenPlaintext == NULL)
exc = EX_MODPARAM;
else if(paramCompressedThenPlaintext->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, setLzw(e, param, &p_etat->cl, 0)); /* 0 : en une fois */
p_etat->cl.inverse = FALSE;
if(paramReverse != NULL)
{
if(paramReverse->type == VAR_DYNAMIC || paramReverse->type == VAR_NUMBER)
{
number inv;
if(var_conv_num(e, paramReverse, &inv))
p_etat->cl.inverse = (inv != 0 ? TRUE : FALSE);
}
}
exc = setError(p_etat, getLzw(e, paramCompressedThenPlaintext, &p_etat->cl, 0)); /* decompression compatible PDF (et GIF si reverse = TRUE), 0 : en une fois */
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "get", 3) == 0)
{
/* decompression du code de param, en une fois */
/* sinon utiliser getinit, getnext, getend */
/*exc = setError(p_etat, EXMOD_xxx);*/
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, getLzw(e, param, &p_etat->cl, 0)); /* 0 : en une fois */
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "xxx", 3) == 0)
{
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
exc = setError(p_etat, EXMOD_xxx);
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
/* **************************************************************************************************** */
+73 -25
View File
@@ -1,22 +1,41 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "lzw.h"
void initLzw(env * e, modContextLzw * cl)
{
cl->allocEntry = 0;
dynInit(e, &cl->code, 4096);
dynInit(e, &cl->w, 256);
}
void freeLzw(env * e, modContextLzw * cl)
{
dynFree(e, &cl->code);
dynFree(e, &cl->w);
}
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
static void InitDict(env * e, modContextLzw * cl)
{
cl->posDict = 0; // prochaine entree
@@ -124,9 +143,21 @@ static void ecrireCode(env * e, modContextLzw * cl, long num)
cl->code.mInternal = b; /* nb bits libres restant */
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/* ***** PUBLIC *************** */
WAPIDECL void initLzw(env * e, modContextLzw * cl)
{
cl->allocEntry = 0;
dynInit(e, &cl->code, 4096);
dynInit(e, &cl->w, 256);
}
long setLzw(env * e, var * clair, modContextLzw * cl, int type)
WAPIDECL void freeLzw(env * e, modContextLzw * cl)
{
dynFree(e, &cl->code);
dynFree(e, &cl->w);
}
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type)
{
/* codage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
@@ -198,10 +229,10 @@ long setLzw(env * e, var * clair, modContextLzw * cl, int type)
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
long getLzw(env * e, var * comp, modContextLzw * cl, int type)
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type)
{
long v; /* code en cours de decodage */
long masque[8] = {0, 1, 3, 7, 15, 31, 63, 127};
long masque[13] = {0, 1, 3, 7, 15, 31, 63, 127, 0, 511, 1023, 2047, 4095}; // les 8 premiers servent au mode normal, les 4 derniers au mode "inverse"
/* decodage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
@@ -225,16 +256,33 @@ long getLzw(env * e, var * comp, modContextLzw * cl, int type)
/* lire les bits pour trouver le prochain code */
c = *pcomp++;
/* */
cl->reste = (cl->reste << 8) | c;
cl->code.mInternal += 8;
if(cl->code.mInternal < cl->bits)
continue;
cl->code.mInternal -= cl->bits; /* maxi 7 bits restants */
if(cl->code.mInternal == 0)
v = cl->reste;
if(cl->inverse) // test, sinon param "inverse"
{
// cas LZW du giff (different de LZW natif/PDF !)
if(cl->code.mInternal == 0)
cl->reste |= c;
else
cl->reste |= (c << cl->code.mInternal);
cl->code.mInternal += 8;
if(cl->code.mInternal < cl->bits)
continue;
v = (cl->reste & masque[cl->bits]);
cl->reste >>= cl->bits;
cl->code.mInternal -= cl->bits;
}
else
v = cl->reste >> cl->code.mInternal;
cl->reste &= masque[cl->code.mInternal];
{
cl->reste = (cl->reste << 8) | c;
cl->code.mInternal += 8;
if(cl->code.mInternal < cl->bits)
continue;
cl->code.mInternal -= cl->bits; /* maxi 7 bits restants */
if(cl->code.mInternal == 0)
v = cl->reste;
else
v = cl->reste >> cl->code.mInternal;
cl->reste &= masque[cl->code.mInternal];
}
/* */
if(v == 256)
{
+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;
}
}
+6
View File
@@ -44,6 +44,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#define WLIBDECL __declspec(dllexport)
#else
#define WLIBDECL
#endif
#ifndef UNIX
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
+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;
}
+64 -31
View File
@@ -1,27 +1,50 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "lzw.h"
/* ******* constantes ********** */
#define PDFFMT_A4P 1 /* A4 portrait */
#define PDFFMT_A4L 2 /* A4 paysage ("landscape") */
#define PDFFMT_A3P 3 /* A3 portrait */
#define PDFFMT_A3L 4 /* A3 paysage */
#define PDFFONT_COURIER 1
#define PDFFONT_COURIER_BOLD 2
#define PDFFONT_COURIER_BOLDOBLIQUE 3
#define PDFFONT_COURIER_OBLIQUE 4
#define PDFFONT_HELVETICA 5
#define PDFFONT_HELVETICA_BOLD 6
#define PDFFONT_HELVETICA_BOLDOBLIQUE 7
#define PDFFONT_HELVETICA_OBLIQUE 8
#define PDFFONT_TIMES_ROMAN 9
#define PDFFONT_TIMES_BOLD 10
#define PDFFONT_TIMES_ITALIC 11
#define PDFFONT_TIMES_BOLDITALIC 12
#define PDFFONT_SYMBOL 13
#define PDFFONT_ZAPFDINGBATS 14
#define PDFFONT_NB 14
enum {
PDFFMT_A4P = 1, /* A4 portrait */
PDFFMT_A4L = 2, /* A4 paysage ("landscape") */
PDFFMT_A3P = 3, /* A3 portrait */
PDFFMT_A3L = 4, /* A3 paysage */
PDFFONT_COURIER = 1,
PDFFONT_COURIER_BOLD = 2,
PDFFONT_COURIER_BOLDOBLIQUE = 3,
PDFFONT_COURIER_OBLIQUE = 4,
PDFFONT_HELVETICA = 5,
PDFFONT_HELVETICA_BOLD = 6,
PDFFONT_HELVETICA_BOLDOBLIQUE = 7,
PDFFONT_HELVETICA_OBLIQUE = 8,
PDFFONT_TIMES_ROMAN = 9,
PDFFONT_TIMES_BOLD = 10,
PDFFONT_TIMES_ITALIC = 11,
PDFFONT_TIMES_BOLDITALIC = 12,
PDFFONT_SYMBOL = 13,
PDFFONT_ZAPFDINGBATS = 14,
PDFFONT_NB = 14
};
/* ***** MACRO ****/
#define RGB(r,g,b) (((((r&255)<<8)+(g&255))<<8)+(b&255))
@@ -31,11 +54,13 @@ typedef struct
Dynamic mPdf; /* PDF en cours de constitution */
Dynamic mPage; /* page en cours */
Dynamic mXref; /* liste des xref du PDF en cours (<1> contient le titre et les dimensions des images) */
Dynamic mImg; /* images en FM, en hexa, BMP 24/32 bpp uniquement (codage RGB) */
Dynamic mImg; /* images en FM, en hexa, BMP 24/32 bpp uniquement (codage RGB) */
Dynamic mInfoPage; /* quand nb pages pas connu a l'init, contient le num obj de chaque page */
long mNbPage; /* nb de pages total du PDF */
long mFormat; /* A4 ou A3 et Paysage ou portrait */
long mLarg, mHaut; /* largeur/hauteur de la page en (mm x 10), selon le format */
long mNbObj; /* pour xref */
long mNbFont, mNbImg, mNbObjFixe;
long mNumPage; /* numero page en cours */
long mLmarg; /* marge gauche en mm x 10 */
@@ -45,18 +70,26 @@ typedef struct
long mDimFont; /* taille fonte */
long mDimFontCadre;
long mDimLig;
Dynamic mFont; /* nom des 14 fontes standards */
Dynamic mFont; /* nom des 14 fontes standards */
Dynamic mEan128; /* codage graphique du cab ean128 */
modContextLzw mCtxLzw; /* gestion compression page lzw */
Dynamic mTmp1, mTmp2; /* temporaire pour le traitement */
Dynamic mTmp1, mTmp2, mTmp3; /* temporaire pour le traitement */
} modContextPdf;
void initPdf(env * e, modContextPdf * ctxPdf);
void freePdf(env * e, modContextPdf * ctxPdf);
int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts);
int endPdf(env * e, modContextPdf * ctxPdf);
int setPdfPage(env * e, modContextPdf * ctxPdf, int compression);
int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt);
int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille);
int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img);
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf);
WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts);
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression);
WAPIDECL int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt);
WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille);
WAPIDECL int setCab128(env * e, modContextPdf * ctxPdf, Dynamic * data, long x, long y, long h);
WAPIDECL int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img);
WAPIDECL int pdfDeleteImage(env * e, modContextPdf * ctxPdf, long img);
WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier);
WAPIDECL int pdfLoadImageGif(env * e, modContextPdf * ctxPdf, Dynamic * fichier);
WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic * lignes, long format);
+307 -92
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,68 +30,70 @@
#include "var.h"
#include "hashtable.h"
/* ============================================================================================= */
#include "pdf.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextPdf cp;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_PDF_INTERNAL_ERR = 1,
EXMOD_PDF_IMGFORMAT = 2,
EXMOD_PDF_PARAMETERSET = 3,
EXMOD_NB = 3
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Internal error",
"Image format unsupported (BMP/GIF only)",
"Incorrect parameterSet's membre"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initPdf(e, &p_etat->cp);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initPdf(e, &p_etat->cp);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
@@ -99,118 +101,331 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
{
//*** code specifique ici
freePdf(e, &p_etat->cp);
// fin liberation specifique module avant arret process
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "beginDoc", 8))
{
// nouveau document pdf
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1->type != VAR_HASHTABLE)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(paramPdfParameterSet->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// lire les infos necessaires a la creation d'un nouveau doc. pdf :
// titre, nb pages, format, fontes utilisees
var * titre, * fontes;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fontes"), &fontes);
if(titre && fontes)
var * titre, * fontes, * nbPage, * format;
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Title"), &titre);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Fonts"), &fontes);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Pages"), &nbPage);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Format"), &format);
if(titre && fontes && nbPage && format)
{
if(titre->type == VAR_DYNAMIC && fontes->type == VAR_DYNAMIC)
exc = setError(p_etat, ! newPdf(e, &p_etat->cp, titre, 1, PDFFMT_A4P, fontes));
if(titre->type == VAR_DYNAMIC && fontes->type == VAR_DYNAMIC &&
(nbPage->type == VAR_NUMBER || nbPage->type == VAR_DYNAMIC) && (format->type == VAR_NUMBER || format->type == VAR_DYNAMIC))
{
number nnbPage, nformat;
if( var_conv_num(e, nbPage, &nnbPage) && var_conv_num(e, format, &nformat) )
exc = setError(p_etat, newPdf(e, &p_etat->cp, titre, nnbPage / NUM_FACTEUR, nformat / NUM_FACTEUR, fontes) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = EX_MODPARAM;
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "endDoc", 6))
{
// finalise le document pdf, et renvoi le contenu dans param1
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfContent = getParam(e, "pdfContent", 10);
if(paramPdfContent == NULL)
exc = EX_MODPARAM;
else
{
int cr = endPdf(e, &p_etat->cp);
if(cr)
{
var_let(e, param1, getPdf(e, &p_etat->cp), FALSE, FALSE);
}
exc = setError(p_etat, ! cr);
var_let(e, paramPdfContent, getPdf(e, &p_etat->cp), FALSE, FALSE);
exc = setError(p_etat, cr ? OK : EXMOD_PDF_INTERNAL_ERR);
}
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addPage", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
// ajouter la page en cours au doucment pdf
exc = setError(p_etat, ! setPdfPage(e, &p_etat->cp, 1)); // 1 = avec compression ; parametrer ?
/* get param in the right order */
// ajouter la page en cours au doucment pdf
exc = setError(p_etat, setPdfPage(e, &p_etat->cp, 1) ? OK : EXMOD_PDF_INTERNAL_ERR); // 1 = avec compression ; parametrer ?
}
/* ============================================================================================= */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addText", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
var * paramString = getParam(e, "string", 6);
if(paramPdfParameterSet == NULL || paramString == NULL)
exc = EX_MODPARAM;
else if(param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramString->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// ajouter le texte
exc = setError(p_etat, ! setPdfText(e, &p_etat->cp, 100, 900, 300, 300, 1, 10, 0, param2));
var * x, * y, * w, * h; // cadre englobant
var * fonte, * taille, * couleur;
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Font"), &fonte);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Size"), &taille);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Color"), &couleur);
if(x && y && w && h && fonte && taille && couleur)
{
number nx, ny, nw, nh, nfonte, ntaille, ncouleur;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
var_conv_num(e, fonte, &nfonte) && var_conv_num(e, taille, &ntaille) && var_conv_num(e, couleur, &ncouleur) )
exc = setError(p_etat, setPdfText(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
nfonte / NUM_FACTEUR, ntaille / NUM_FACTEUR, ncouleur / NUM_FACTEUR, paramString) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------- */
else if(modFnIs(e, "addCab128", 9))
{
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
var * paramString = getParam(e, "string", 6);
if(paramPdfParameterSet == NULL || paramString == NULL)
exc = EX_MODPARAM;
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramString->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// ajouter le texte
var * x, * y, * h; // position et hauteur du CAB
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
if(x && y && h)
{
number nx, ny, nh;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, h, &nh) )
exc = setError(p_etat, setCab128(e, &p_etat->cp, paramString, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nh / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ---------------------------------------------------- */
else if(modFnIs(e, "addGraph", 8))
{
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(paramPdfParameterSet->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * w, * h; // cadre englobant
var * couleurTrait, * couleurRemplissage, * epaisseur, * pointille, * type;
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "StrokeColor"), &couleurTrait);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "FillColor"), &couleurRemplissage);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "LineThickness"), &epaisseur);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Dotted"), &pointille);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Type"), &type);
if(x && y && w && h && couleurTrait && couleurRemplissage && epaisseur && pointille && type)
{
number nx, ny, nw, nh, ntrait, nrempl, nepais, npoint;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
type->type == VAR_DYNAMIC && var_conv_num(e, couleurTrait, &ntrait) && var_conv_num(e, couleurRemplissage, &nrempl) &&
var_conv_num(e, epaisseur, &nepais) && var_conv_num(e, pointille, &npoint) )
exc = setError(p_etat, setPdfGraph(e, &p_etat->cp, *type->mPtr, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
ntrait / NUM_FACTEUR, nrempl / NUM_FACTEUR, nepais / NUM_FACTEUR, npoint / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ---------------------------------------------------- */
else if(modFnIs(e, "addImage", 8))
{
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 10);
if(paramPdfParameterSet == NULL)
exc = EX_MODPARAM;
else if(paramPdfParameterSet->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * img; // cadre englobant et n° image
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "ImageIndex"), &img);
if(x && y && img)
{
number nx, ny, nimg;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, img, &nimg) )
exc = setError(p_etat, setPdfImage(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nimg / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ---------------------------------------------------- */
else if(modFnIs(e, "loadImage", 9))
{
/* get param in the right order */
var * paramImage = getParam(e, "image", 5);
var * paramFormat = getParam(e, "format", 6);
if(paramImage == NULL || paramFormat == NULL)
exc = EX_MODPARAM;
else if(paramImage->type != VAR_DYNAMIC || paramFormat->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynCompare(e, paramFormat, CMP_EQ, "BMP", 3))
exc = setError(p_etat, pdfLoadImageBmp(e, &p_etat->cp, paramImage) ? OK : EXMOD_PDF_INTERNAL_ERR);
else if(dynCompare(e, paramFormat, CMP_EQ, "GIF", 3))
exc = setError(p_etat, pdfLoadImageGif(e, &p_etat->cp, paramImage) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_IMGFORMAT);
}
}
/* ---------------------------------------------------- */
else if(modFnIs(e, "delImage", 8))
{
/* get param in the right order */
var * paramImage = getParam(e, "imageIndex", 10);
if(paramImage == NULL)
exc = EX_MODPARAM;
else if(paramImage->type != VAR_NUMBER && paramImage->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number indice;
if(var_conv_num(e, paramImage, &indice))
exc = setError(p_etat, pdfDeleteImage(e, &p_etat->cp, indice / NUM_FACTEUR) ? OK : EXMOD_PDF_INTERNAL_ERR);
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ---------------------------------------------------- */
else if(modFnIs(e, "listing", 7))
{
/* get param in the right order */
var * paramPdfParameterSet = getParam(e, "pdfParameterSet", 15);
var * paramTextThenPdfContent = getParam(e, "textThenPdfContent", 18);
if(paramPdfParameterSet == NULL || paramTextThenPdfContent == NULL)
exc = EX_MODPARAM;
else if(paramPdfParameterSet->type != VAR_HASHTABLE || paramTextThenPdfContent->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
var * titre, * format;
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Title"), &titre);
hashtable_do(e, HASH_READ, paramPdfParameterSet, copy_nom(e, "Format"), &format);
if(titre && format)
{
if(titre->type == VAR_DYNAMIC && (format->type == VAR_NUMBER || format->type == VAR_DYNAMIC))
{
number nformat;
if( var_conv_num(e, format, &nformat) )
{
int cr = pdfList(e, &p_etat->cp, titre, paramTextThenPdfContent, nformat / NUM_FACTEUR);
if(cr)
var_let(e, paramTextThenPdfContent, getPdf(e, &p_etat->cp), FALSE, FALSE);
exc = setError(p_etat, cr ? OK : EXMOD_PDF_INTERNAL_ERR);
}
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
else
exc = setError(p_etat, EXMOD_PDF_PARAMETERSET);
}
}
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+612 -151
View File
@@ -1,6 +1,38 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "pdf.h"
#include <string.h>
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
//
// creation fichier PDF
//
@@ -133,10 +165,75 @@
#include "stdio.h"
#define PDF_CONV1 72000
#define PDF_CONV2 2540
enum {
PDF_CONV1 = 72000,
PDF_CONV2 = 2540
};
/* valeur en dixieme de mm * CONV11 / CONV2 = valeur en unites pdf x 100 (72 dpi = 72 points par pouce ; 1 pouce = 25.4) */
// dynOconv ne sert pas ailleurs : a voir a mettre dans conv.h ? autre ? (revoir mod Horodate)
#include "time.h"
static long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format)
{
/* a revoir pour UTF8 ? (Base64 ?) oui pour D car d'autres cars utf8 peuvent etre dans la chaine */
char tmp[5];
//
switch(*format++)
{
case 'D': // obsolete ? utiliser le mod Horodate
{
struct tm * ptm;
/* conversion date/heure : format interne = time_t unix sur 32 bits */
time_t tm;
if(this->mLg == 0)
{
tm = time(NULL);
ptm = gmtime(&tm);
}
else
{
tm = dynToNum(e, this, DYN_NONE, 10); /* pas de signe, lg max sur 32 bits = 10 chiffres */
if(this->mInternal == DYN_ERR)
return DYN_ERR; /* pbm de conversion numerique */
ptm = localtime(&tm);
}
/* analyse formatage demande */
dynLet(e, resultat, NULL, DYN_LGNONE);
tmp[1] = 0;
while((tmp[0] = *format++))
switch(tmp[0])
{
case 'Y':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_year + 1900, DYN_NONE, 4), 4);
break;
case 'y':
dynConcatSz(e, resultat, Int32ToSz((ptm->tm_year + 1900) % 100, DYN_NONE, 2), 2);
break;
case 'M':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mon + 1, DYN_NONE, 2), 2);
break;
case 'D':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mday, DYN_NONE, 2), 2);
break;
case 'h':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_hour, DYN_NONE, 2), 2);
break;
case 'm':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_min, DYN_NONE, 2), 2);
break;
case 's':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_sec, DYN_NONE, 2), 2);
break;
default:
dynConcatSz(e, resultat, tmp, 1);
break;
}
break;
}
}
return DYN_OK;
}
/* PRIVATE *****************************************************/
static int pdfEchap(env * e, Dynamic * resultat, Dynamic * chaine)
{
@@ -169,6 +266,13 @@ static int setXref(env * e, modContextPdf * ctxPdf)
return ! dynConcatSz(e, &ctxPdf->mXref, sFM, 1) && ! dynConcatSz(e, &ctxPdf->mXref, Int64ToSz(e, (ent64s)ctxPdf->mPdf.mLg, FALSE, 10), DYN_LGNONE); // verif leftpad ok (idem "%010ld") !! TODO !!
}
static int majXref(env * e, modContextPdf * ctxPdf, int numObj)
{
/* MAJ table xref quand l'objet est mis "apres" la declaration */
dynLet(e, &ctxPdf->mTmp3, Int64ToSz(e, (ent64s)ctxPdf->mPdf.mLg, FALSE, 10), 10);
return dynStore(e, &ctxPdf->mXref, numObj + 1, DYN_NONE, &ctxPdf->mTmp3, cFM, DYN_NONE);
}
static char table100[400] = ".00\0.01\0.02\0.03\0.04\0.05\0.06\0.07\0.08\0.09\0"
".10\0.11\0.12\0.13\0.14\0.15\0.16\0.17\0.18\0.19\0"
".20\0.21\0.22\0.23\0.24\0.25\0.26\0.27\0.28\0.29\0"
@@ -221,8 +325,54 @@ static int fmtc(env * e, Dynamic * res, long coul)
return cr;
}
static void convertHexaRGBToBinLzw(env * e, modContextPdf * ctxPdf)
{
// ctxPdf->mTmp1 contient les donnees en entree, et ctxPdf->mTmp2 en sortie le lzw binaire
// conversion de mTmp1 RGB hexa en binaire dans mTmp2
dynSetLen(e, &ctxPdf->mTmp2, 0);
long i, nb = ctxPdf->mTmp1.mLg / 6; // RRGGBB = 6 octets
octet * p = ctxPdf->mTmp1.ptr;
char res[4] = {0};
for(i = 0; i < nb; i++, p += 6)
{
dynConvertCharHexaToChar(*p, *(p+1), res);
dynConvertCharHexaToChar(*(p+2), *(p+3), res + 1);
dynConvertCharHexaToChar(*(p+4), *(p+5), res + 2);
dynConcatSz(e, &ctxPdf->mTmp2, res, 3);
}
// compression lzw de e->mTmp2
setLzw(e, &ctxPdf->mTmp2, &ctxPdf->mCtxLzw, 0);
}
static void graphCab128(env * e, modContextPdf * ctxPdf, long code, long * x, long y, long h)
{
long ec = 0, x1, i, largeur = 3; /* largeur des barres, pour un 1 */
long nb = (code == 106 ? 13 : 11); /* code stop = 13 bits, les autres = 11 bits */
code = code * 11;
for(i = 0; i < nb; i++, code++)
{
if(ctxPdf->mEan128.mPtr[code] == '1')
{
if( ! ec)
{
ec = 1;
x1 = *x;
}
}
else if(ec)
{
ec = 0;
setPdfGraph(e, ctxPdf, 'R', x1, y, *x - x1, h, -1, RGB(0,0,0), 0, 0);
}
/* */
*x += largeur;
}
if(ec)
setPdfGraph(e, ctxPdf, 'R', x1, y, *x - x1, h, -1, RGB(0,0,0), 0, 0);
}
/* PUBLIC ************************************************************************/
void initPdf(env * e, modContextPdf * ctxPdf)
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf)
{
ctxPdf->mLmarg = 100; /* dixieme de mm ( = 1 cm ici) */
ctxPdf->mRmarg = 100;
@@ -235,38 +385,63 @@ void initPdf(env * e, modContextPdf * ctxPdf)
dynInit(e, &ctxPdf->mFont, 256);
dynInit(e, &ctxPdf->mTmp1, 1024);
dynInit(e, &ctxPdf->mTmp2, 1024);
dynInit(e, &ctxPdf->mTmp3, 1024);
dynInit(e, &ctxPdf->mPage, 4096);
dynInit(e, &ctxPdf->mPdf, 8192);
ctxPdf->mPdf.type = VAR_DYNAMIC;
dynInit(e, &ctxPdf->mXref, 1024);
dynInit(e, &ctxPdf->mImg, 2048);
dynInit(e, &ctxPdf->mInfoPage, 1024);
dynInit(e, &ctxPdf->mEan128, 1200);
/* nom des fontes standards */
dynLet(e, &ctxPdf->mFont, "Courier,Courier-Bold,Courier-BoldOblique,Courier-Oblique,Helvetica,Helvetica-Bold,Helvetica-BoldOblique,Helvetica-Oblique,Times-Roman,Times-Bold,Times-Italic,Times-BoldItalic,Symbol,ZapfDingbats", DYN_LGNONE);
dynLet(e, &ctxPdf->mFont, "Courier,Courier-Bold,Courier-BoldOblique,Courier-Oblique,Helvetica,Helvetica-Bold,Helvetica-BoldOblique,Helvetica-Oblique,"
"Times-Roman,Times-Bold,Times-Italic,Times-BoldItalic,Symbol,ZapfDingbats", DYN_LGNONE);
dynConvert(e, &ctxPdf->mFont, ",", sFM);
//
initLzw(e, &ctxPdf->mCtxLzw);
//
// code ean 128 : https://fr.wikipedia.org/wiki/Code_128
// Checksum = (StartCode + 1 x valeur1 + 2 x valeur2 + 3 x valeur3 + ...) modulo 103 (valeur de 0 a 102)
dynLet(e, &ctxPdf->mEan128,
"11011001100110011011001100110011010010011000100100011001000100110010011001000100110001001000110010011001001000" // 0 9
"11001000100110001001001011001110010011011100100110011101011100110010011101100100111001101100111001011001011100" // 10 19
"11001001110110111001001100111010011101101110111010011001110010110011100100110111011001001110011010011100110010" // 20 29
"11011011000110110001101100011011010100011000100010110001000100011010110001000100011010001000110001011010001000" // 30 39
"11000101000110001000101011011100010110001110100011011101011101100010111000110100011101101110111011011010001110" // 40 49
"11000101110110111010001101110001011011101110111010110001110100011011100010110111011010001110110001011100011010" // 50 59
"11101111010110010000101111000101010100110000101000011001001011000010010000110100001011001000010011010110010000" // 60 69
"10110000100100110100001001100001010000110100100001100101100001001011001010000111101110101100001010010001111010" // 70 79
"10100111100100101111001001001111010111100100100111101001001111001011110100100111100101001111001001011011011110" // 80 89
"11011110110111101101101010111100010100011110100010111101011110100010111100010111101010001111010001010111011110" // 90 99
"1011110111011101011110111101011101101000010011010010000110100111001100011101011", 1180); // 100 106 (106 sur 13 bits au lieu de 11 pour tous les autres)
// codes 0 - 94 : codes ascii de 32 a 126 (code 128B)
// codes 95:DEL 96:FNC3 97:FNC2 98:SHIFTA 99:CODEC 100:CODEB 101:CODEA 102:FNC1 103:StartA 104:StartB 105:StartC 106:Stop(13 bits)
// code EAN128B : startB_104 + valeur1 + valeur2 + valeur3 + ... + checksum + Stop_106
}
void freePdf(env * e, modContextPdf * ctxPdf)
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf)
{
freeLzw(e, &ctxPdf->mCtxLzw);
/* */
dynFree(e, &ctxPdf->mFont);
dynFree(e, &ctxPdf->mTmp1);
dynFree(e, &ctxPdf->mTmp2);
dynFree(e, &ctxPdf->mTmp3);
dynFree(e, &ctxPdf->mPage);
dynFree(e, &ctxPdf->mPdf);
dynFree(e, &ctxPdf->mXref);
dynFree(e, &ctxPdf->mImg);
dynFree(e, &ctxPdf->mInfoPage);
dynFree(e, &ctxPdf->mEan128);
}
int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts)
WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts)
{
long i, j, cpt, nbp;
long nb_img, nb_obj_entete, nb_font, nb_obj_fixe = 3;
long nb_img, nb_obj_entete, nb_font;
int cr = TRUE;
/* controles */
if(nb_page < 1)
if(nb_page < 0)
return FALSE;
/* */
switch(format)
@@ -306,9 +481,11 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
/* */
nb_font = dynDcount(e, fonts, cFM, DYN_NONE, DYN_NONE);
nb_img = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE);
nb_obj_entete = nb_obj_fixe + nb_font + nb_img;
ctxPdf->mNbObjFixe = 3;
nb_obj_entete = ctxPdf->mNbObjFixe + nb_font + nb_img;
ctxPdf->mNbObj = nb_obj_entete + ctxPdf->mNbPage;
ctxPdf->mNumPage = 0;
ctxPdf->mNbImg = nb_img;
//
dynLet(e, &ctxPdf->mPdf, "%PDF-1.2\r\n", DYN_LGNONE);
// objet racine root
@@ -319,22 +496,28 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
dynConcatSz(e, &ctxPdf->mPdf, "2 0 obj << /Producer (WPDF) /Author (WPDF) /Title (", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1); /* titre "echape" */
dynConcatSz(e, &ctxPdf->mPdf, ") /CreationDate (", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, "20000101140000", DYN_LGNONE); // TODO date courante YMDhms dynOconv(e, ...)
dynSetLen(e, &ctxPdf->mTmp1, 0); // empty => oconv will convert time of the day
dynOconv(e, &ctxPdf->mTmp1, &ctxPdf->mTmp2, "DYMDhmsZ");
dynConcatSz(e, &ctxPdf->mPdf, "D:", 2);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
dynConcatSz(e, &ctxPdf->mPdf, ") >> endobj\r\n", DYN_LGNONE);
setXref(e, ctxPdf);
// liste des pages
cpt = nb_obj_entete;
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNbPage; i++)
if(ctxPdf->mNbPage > 0)
{
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
// liste des pages
cpt = nb_obj_entete;
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNbPage; i++)
{
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ++cpt, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
} /* si nb page pas connu, sera mis a la fin */
/* liste des fontes, prendre celles utilisees */
cpt = nb_obj_fixe;
cpt = ctxPdf->mNbObjFixe;
for(i = 1, nbp = 0; i <= PDFFONT_NB; i++)
{
dynField(e, &ctxPdf->mFont, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
@@ -349,6 +532,9 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
dynConcatSz(e, &ctxPdf->mPdf," /Encoding << /Type /Encoding /BaseEncoding /WinAnsiEncoding >> >> endobj\r\n", DYN_LGNONE);
}
}
if(nbp != nb_font)
return FALSE;
ctxPdf->mNbFont = nbp;
/* liste des images */
for(i = 1; i <= nb_img; i++)
{
@@ -365,11 +551,12 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mXref, " 0 0 ", DYN_LGNONE);
dynConcat(e, &ctxPdf->mXref, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf," /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /ASCIIHexDecode /Length ", DYN_LGNONE); // TODO remplacer /ASCIIHexDecode par /LZW...
dynConcatSz(e, &ctxPdf->mPdf," /BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter /LZWDecode /Length ", DYN_LGNONE); // /LZWDecode remplace /ASCIIHexDecode
dynField(e, &ctxPdf->mImg, &ctxPdf->mTmp1, i, 3, cFM, cVM, 1); // vm1 = larg (w) VM2 = haut (h) VM3 = bitmap 32bpp hexa RGBRGBRGBRGB
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mTmp1.mLg, FALSE, 0), DYN_LGNONE);
convertHexaRGBToBinLzw(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mTmp2.mLg, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " >>\r\nstream\r\n", DYN_LGNONE);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp2);
dynConcatSz(e, &ctxPdf->mPdf,"\r\nendstream\r\nendobj\r\n", DYN_LGNONE);
}
/* definition de chaque page */
@@ -386,7 +573,7 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
dynConcatSz(e, &ctxPdf->mPdf, "/F", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + nb_obj_fixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
@@ -397,7 +584,7 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
dynConcatSz(e, &ctxPdf->mPdf, "/Img", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + nb_obj_fixe + nbp, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe + nbp, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R", DYN_LGNONE);
if(j == nb_img)
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
@@ -409,9 +596,24 @@ int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long
return cr;
}
int endPdf(env * e, modContextPdf * ctxPdf)
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf)
{
long i, nb; /* nb xref */
if(ctxPdf->mNbPage == 0)
{
majXref(e, ctxPdf, 3);
// liste des pages
dynConcatSz(e, &ctxPdf->mPdf,"3 0 obj << /Type /Pages /Count ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNumPage, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf," /Kids [ ", DYN_LGNONE);
for(i = 1; i <= ctxPdf->mNumPage; i++)
{
dynField(e, &ctxPdf->mInfoPage, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf,"] >> endobj\r\n", DYN_LGNONE);
}
setXref(e, ctxPdf);
dynConcatSz(e, &ctxPdf->mPdf, "xref\r\n0 ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj + 1, FALSE, DYN_NONE), DYN_LGNONE);
@@ -422,7 +624,7 @@ int endPdf(env * e, modContextPdf * ctxPdf)
dynConcatSz(e, &ctxPdf->mPdf, "\r\n0000000000 65535 f\r\n", DYN_LGNONE);
else
{
dynField(e, &ctxPdf->mXref, &ctxPdf->mTmp1, i, DYN_NONE, cFM, DYN_NONE, 1);
dynField(e, &ctxPdf->mXref, &ctxPdf->mTmp1, i, 1, cFM, cVM, 1); // VM1 a cause des images (x et y dans xref<x,2>...)
dynConcat(e, &ctxPdf->mPdf, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPdf, " 00000 n\r\n", DYN_LGNONE);
}
@@ -435,19 +637,52 @@ int endPdf(env * e, modContextPdf * ctxPdf)
return TRUE;
}
Dynamic * getPdf(env * e, modContextPdf * ctxPdf)
WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf)
{
return &ctxPdf->mPdf;
}
int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
{
int cr = TRUE;
int cr = TRUE, j;
/* compression = 0 : pas de compression LZW */
/* 1 : compression LZW en binaire */
setXref(e, ctxPdf);
ctxPdf->mNbObj++;
ctxPdf->mNumPage++;
if(ctxPdf->mNbPage == 0)
{
setXref(e, ctxPdf);
dynStoreNumber(e, &ctxPdf->mInfoPage, ctxPdf->mNumPage, DYN_NONE, ctxPdf->mNbObj, cFM, DYN_NONE); /* num objet declaration page (pas le contenu) */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj++, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Type /Page /Parent 3 0 R /MediaBox [ 0 0 ", DYN_LGNONE);
fmt2(e, &ctxPdf->mPdf, ctxPdf->mLarg, ctxPdf->mHaut);
dynConcatSz(e, &ctxPdf->mPdf," ] /Resources << /Font << ", DYN_LGNONE);
for(j = 1; j <= ctxPdf->mNbFont; j++)
{
dynConcatSz(e, &ctxPdf->mPdf, "/F", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
for(j = 1; j <= ctxPdf->mNbImg; j++)
{
if(j == 1)
dynConcatSz(e, &ctxPdf->mPdf, "/XObject << ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, "/Img", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, j + ctxPdf->mNbObjFixe + ctxPdf->mNbFont, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R", DYN_LGNONE);
if(j == ctxPdf->mNbImg)
dynConcatSz(e, &ctxPdf->mPdf, ">> ", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPdf, ">> /Contents ", DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 R >> endobj\r\n", DYN_LGNONE);
}
setXref(e, ctxPdf);
/* ajout du code "PDF" directement */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mNbObj, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " 0 obj << /Length ", DYN_LGNONE);
@@ -460,10 +695,8 @@ int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
}
else
{
// compression LZW du stream de la page
//ctxPdf->mCtxLzw.compress_do(0, (unsigned char *)ctxPdf->mPage.mPtr, ctxPdf->mPage.mLg); // verif
/* compression LZW du stream de la page */
setLzw(e, &ctxPdf->mPage, &ctxPdf->mCtxLzw, 0);
//ctxPdf->mPage = ctxPdf->mLzw.getCode(); // verif
/* */
dynConcatSz(e, &ctxPdf->mPdf, Int64ToSz(e, ctxPdf->mPage.mLg, FALSE, DYN_NONE), DYN_LGNONE);
dynConcatSz(e, &ctxPdf->mPdf, " /Filter /LZWDecode >>\r\nstream\r\n", DYN_LGNONE);
@@ -475,7 +708,7 @@ int setPdfPage(env * e, modContextPdf * ctxPdf, int compression)
return cr;
}
int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt)
WAPIDECL int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt)
{
int cr = TRUE;
/* x,y,w,h en mm, font de 1 a PDF_FONT_NB, couleur avec RGB(r,g,b) */
@@ -495,7 +728,7 @@ int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h,
return cr;
}
int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille)
WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille)
{
int cr = TRUE;
/* x,y,w,h en mm, font de 1 a PDF_FONT_NB, coul_trait/coul_rempl avec RGB(r,g,b), epaisseur et pointille de 0 a 9 */
@@ -549,7 +782,34 @@ int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long
return cr;
}
int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
WAPIDECL int setCab128(env * e, modContextPdf * ctxPdf, Dynamic * data, long x, long y, long h)
{
long cpt_char, code, x_orig = x, checksum = 104; /* StartB */
code = 104; /* StartB */
graphCab128(e, ctxPdf, code, &x, y, h);
for(cpt_char = 0; cpt_char < data->mLg; cpt_char++)
{
code = (long)(data->ptr[cpt_char]);
if(code > 31 && code < 127)
{
code -= 32;
graphCab128(e, ctxPdf, code, &x, y, h);
checksum += code * (cpt_char + 1);
}
/* sinon, caractere non gere en Code128 : RAF */
}
code = checksum % 103;
graphCab128(e, ctxPdf, code, &x, y, h);
code = 106; /* Stop */
graphCab128(e, ctxPdf, code, &x, y, h);
/* */
dynLet(e, &ctxPdf->mTmp3, "*", 1);
dynConcat(e, &ctxPdf->mTmp3, data);
dynConcatSz(e, &ctxPdf->mTmp3, "*", 1);
return setPdfText(e, ctxPdf, x_orig, y - h/2, x - x_orig, 80, 1, 8, RGB(0,0,0), &ctxPdf->mTmp3); // utilise la premiere fonte declaree utilisee (1), taille 8, en noir
}
WAPIDECL int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
{
int cr = TRUE;
/* x,y en mm, image numero <img> */
@@ -567,121 +827,322 @@ int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img)
return cr;
}
/* debug TODO ---------------------------------------- */
//int pdfChargeImageRGB(env * e, Dynamic * pixel)
WAPIDECL int pdfDeleteImage(env * e, modContextPdf * ctxPdf, long img)
{
// delete image number <img>, if 0 delete all
if(img > 0)
dynDel(e, &ctxPdf->mImg, img, DYN_NONE, cFM, DYN_NONE, 1);
else
dynSetLen(e, &ctxPdf->mImg, 0);
return TRUE;
}
//int pdfLoadImageRGB(env * e, Dynamic * pixel)
//{
// /* TODO png, jpeg,... en amont*/
// return TRUE;
//}
//
//int pdfChargeImageBmp(env * e, char * fichier)
//{
// long bpp, larg, haut, offset, par_ligne;
// char * p; /* pour simplifier le code... */
// long i, j, pos;
// /* lecture fichier */
// if(!ctxPdf->mTmp1.read(fichier))
// return FALSE;
// // controle du bitmap avant memorisation
// p = ctxPdf->mTmp1.getPtr();
// if(p[0] != 'B' && p[1] != 'M')
// return FALSE; /* pas un fichier .bmp */
// //
// bpp = p[28];
// if(bpp != 24 && bpp != 32)
// return FALSE; /* uniquement les fichiers bmp encodes en 24bpp ou 32bpp */
// bpp = bpp >> 3;
// /* */
// offset = (p[11]<<8) + p[10];
// larg = (p[19]<<8) + p[18];
// haut = (p[23]<<8) + p[22];
// par_ligne = larg * bpp; /* nb octets par ligne */
// if((par_ligne&3) != 0)
// par_ligne += (4 - (par_ligne&3));
// /* la bitmap en hexa fera une taille de larg*haut*3*2 */
// if(!ctxPdf->mImg.ctrl(ctxPdf->mImg.getLen() + larg * haut * 6 + 13, TRUE)) /* 13: inclut largeur/hauteur et séparateurs FM VM */
// return FALSE;
// //
// if(ctxPdf->mImg.getLen() != 0)
// {
// ctxPdf->mImg.concat(sFM);
// }
// ctxPdf->mImg.concat(larg, "%ld" sVM);
// ctxPdf->mImg.concat(haut, "%ld" sVM);
// // boucle sur chaque pixel
// for(i = haut-1; i >= 0; i--)
// for(j = 0; j < larg; j++)
// {
// pos = offset + j*bpp + i*par_ligne;
// ctxPdf->mImg.concat( (((p[pos+2]<<8)+p[pos+1])<<8)+p[pos], "%6X");
// }
// return TRUE;
//}
//
//int pdfList(env * e, char * titre, Dynamic & lignes, long format, long compression)
//{
// long nbPage, nbLig, nbLigPage, nbColPage;
// long iPage, iLig, iPos;
// long tmp;
// // enchaine automatiquement les fonctions pour creer un pdf de type "listing" (log ou programme)
// // police Courrier taille 9 en A4 =>
// // paysage : 60 lignes 145 colonnes
// // portrait : 87 lignes 99 colonnes
// if(format == PDF_A4P)
// {
// // portrait
// nbLigPage = 87;
// nbColPage = 99;
// }
// else if(format == PDF_A4L)
// {
// // paysage (Landscape)
// nbLigPage = 60;
// nbColPage = 145;
// }
// else
// return FALSE; // format non pris en charge
// //
// lignes.erase("\r");
// nbLig = lignes.dcount(10); // \n
// if(nbLig == 0)
// nbPage = 1;
// else
// nbPage = (nbLig - 1) / nbLigPage + 1;
// //
// if(!ctxPdf->nouveau(titre, nbPage, format))
// return FALSE; // erreur
// //
// iPos = 1;
// for(iPage = 1; iPage <= nbPage; iPage++)
// {
// //if(logo_societe(mLarg * 10 / mRatio - 20, mHaut * 10 / mRatio - 20))
// // ctxPdf->mPage.concat(mTmp1);
// ctxPdf->mPage.concat("BT /F1 9 Tf ");
// ctxPdf->mPage.concat(ctxPdf->mRatio * mLmarg / 100, "%ld.");
// ctxPdf->mPage.concat(ctxPdf->mRatio * mLmarg % 100, "%ld ");
// tmp = mHaut * 10 - (ctxPdf->mRatio * mHmarg);
// ctxPdf->mPage.concat(tmp / 100, "%ld.");
// ctxPdf->mPage.concat(tmp % 100, "%ld");
// ctxPdf->mPage.concat(" Td 9 TL\r\n");
// //
// for(iLig = 1; iLig <= nbLigPage && iPos <= nbLig; iLig++)
// {
// lignes.field(10, iPos++, mTmp1); // 10 = \n
// mTmp1.substr(0, nbColPage, mTmp2); // tronque au nb de colonnes max
// ctxPdf->echap_txt(mTmp1, mTmp2.getPtr());
// ctxPdf->mPage.concat("(");
// ctxPdf->mPage.concat(mTmp1);
// ctxPdf->mPage.concat(") '\r\n");
// }
// //
// ctxPdf->mPage.concat("ET\r\n");
// //
// if(!ctxPdf->page(compression))
// return FALSE; // erreur
// }
// //
// return ctxPdf->termine();
//}
/* ******************************************************** */
WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
{
long bpp, larg, haut, offset, par_ligne;
octet * p; /* pour simplifier le code... */
long i, j, pos, ind;
/* lecture fichier */
if(!fichier)
return FALSE;
if(fichier->type != VAR_DYNAMIC)
return FALSE;
// controle du bitmap avant memorisation
p = fichier->ptr;
if(p[0] != 'B' && p[1] != 'M')
return FALSE; /* pas un fichier .bmp */
//
bpp = p[28];
if(bpp != 24 && bpp != 32)
return FALSE; /* uniquement les fichiers bmp encodes en 24bpp ou 32bpp */
bpp = bpp >> 3;
/* */
offset = (p[11] << 8) + p[10];
larg = (p[19] << 8) + p[18];
haut = (p[23] << 8) + p[22];
par_ligne = larg * bpp; /* nb octets par ligne */
if((par_ligne & 3) != 0)
par_ligne += (4 - (par_ligne & 3));
/* la bitmap en hexa fera une taille de larg*haut*3*2 */
ind = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE) + 1;
dynStoreNumber(e, &ctxPdf->mImg, ind, 1, larg, cFM, cVM);
dynStoreNumber(e, &ctxPdf->mImg, ind, 2, haut, cFM, cVM);
dynConcatSz(e, &ctxPdf->mImg, sVM, 1);
// boucle sur chaque pixel
for(i = haut-1; i >= 0; i--)
for(j = 0; j < larg; j++)
{
pos = offset + j * bpp + i * par_ligne;
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos + 2]), 2);
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos + 1]), 2);
dynConcatSz(e, &ctxPdf->mImg, dynConvertCharToCharHexa(p[pos]), 2);
}
//printf("Image:\n%s\nlarg:%ld haut:%ld bpp:%ld ind:%ld parligne:%ld lenfichier:%lld\n", ctxPdf->mImg.mPtr, larg, haut, bpp, ind, par_ligne, fichier->mLg);
return TRUE;
}
WAPIDECL int pdfLoadImageGif(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
{
/* https://www.fileformat.info/format/gif/egff.htm */
long larg, haut, offset, ind;
long gctEntry, gct;
long lctEntry, lct, interlace;
octet * p; /* pour simplifier le code... */
/* lecture fichier */
if(!fichier)
{
return FALSE;
}
if(fichier->type != VAR_DYNAMIC)
return FALSE;
/* controle du GIF avant memorisation */
p = fichier->ptr;
if(fichier->mLg < 13)
{
return FALSE;
}
if(strncmp((char *)p, "GIF87a", 6) != 0 && strncmp((char *)p, "GIF89a", 6) != 0)
{
return FALSE; /* pas un fichier GIF */
}
if(p[fichier->mLg - 1] != '\x3B')
return FALSE; /* pas un fichier GIF */
/* les entiers sont en little-endian */
larg = (p[7] << 8) + p[6];
haut = (p[9] << 8) + p[8];
//backColor = p[11];
gct = ((p[10] & 0x80) != 0); /* presence d'une global color table */
//gctSort = ((p[10] & 0x08) != 0); /* tri de la global color table */
gctEntry = 1 << ((p[10] & 0x07) + 1); /* taille de la global color table (max 256 entrees, chacune en RGB, donc x3) */
//gctColResolution = ((p[10] & 0x70) >> 4) + 1; /* nombre de bits par couleur (max 8) */
offset = 13;
if(gct)
{
gct = offset; /* offset de la gct dans le fichier */
offset += gctEntry * 3;
}
while(offset < fichier->mLg && p[offset] == '\x21')
{
/* extension, GIF89a only */
offset++;
if(offset < fichier->mLg && p[offset] == 0xF9) /* ATTENTION : un car est signé => '\xF9' est négatif !!! */
{
/* graphics control extension */
if(fichier->mLg < offset + 7)
return FALSE;
offset += 7;
}
else if(offset < fichier->mLg && p[offset] == 0xFE) /* ATTENTION : un car est signé => '\xFE' est négatif !!! */
{
/* comment extension */
if(fichier->mLg < offset + 2)
return FALSE;
/* "sauter" tous les blocks de commentaire */
offset++;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else if(offset < fichier->mLg && p[offset] == 0xFF) /* ATTENTION : un car est signé => '\xFF' est négatif !!! */
{
/* application extension */
if(fichier->mLg < offset + 13)
return FALSE;
/* "sauter" tous les blocks data */
offset += 13;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else if(offset < fichier->mLg && p[offset] == '\x01')
{
/* plaintext extension */
if(fichier->mLg < offset + 14)
return FALSE;
/* "sauter" tous les blocks data */
offset += 14;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else
return FALSE; /* unknown extension : erreur */
}
/* ici, offset pointe sur la premier Local Image Descriptor */
if(fichier->mLg < offset + 10)
return FALSE; /* pas de partie image dans le fichier */
if(p[offset] != '\x2C')
return FALSE; /* pas de Local Image Descriptor */
/* */
larg = (p[offset + 6] << 8) + p[offset + 5];
haut = (p[offset + 8] << 8) + p[offset + 7];
lct = ((p[offset + 9] & 0x01) != 0); /* presence d'une local color table */
//lctSort = ((p[offset + 9] & 0x04) != 0); /* tri de la local color table */
interlace = ((p[offset + 9] & 0x02) != 0); /* interlace */
lctEntry = 1 << (((p[offset + 9] & 0xE0) >> 5) + 1); /* taille de la local color table (max 256 entrees, chacune en RGB, donc x3) */
offset += 10;
if(lct)
{
lct = offset; /* offset de la lct dans le fichier */
offset += lctEntry * 3;
}
/* decodage lzw de l'image a faire */
Dynamic gif, img, entre; /* gif = image decodee RGB, img = lzw decode, entre = gestion lignes entrelacees */
dynInit(e, &img, 4096);
/* mettre le decode dans img */
modContextLzw ctxLzw;
initLzw(e, &ctxLzw);
ctxLzw.inverse = TRUE; // lzw gif specifique
long type = 0; /* type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, 0 : un seul appel */
/* */
offset++; /* sauter le premier octet = lzw min code size */
while(offset < fichier->mLg && p[offset])
{
if(offset + p[offset] + 1 >= fichier->mLg)
printf("Erreur block lzw data gif\n"); /* TODO erreur de format : block plus grand que le reste du fichier */
if(p[offset + p[offset] + 1])
type = (type == 0) ? 1 : 2; /* pas le dernier bloc */
else
type = (type == 0 ? 0 : 3); /* dernier bloc */
/* */
memcopie(img.ptr, p + offset + 1, p[offset]);
img.mLg = p[offset];
/* */
getLzw(e, &img, &ctxLzw, type);
/* */
offset += p[offset] + 1;
}
/* TODO gerer erreurs (lg ko, lzw ko) */
freeLzw(e, &ctxLzw);
/* les lignes de l'image sont dans l'ordre de haut en bas, de gauche a droite
un octet par pixel donnant l'index soit dans la lct soit la gct de la couleur du pixel
si mode entrelace : les lignes sont dans l'ordre 0, +8, 4, +8, 2, +4, 1, +2
*/
//printf("avant image: larg %ld, haut %ld, offset %ld, val %d, gct %ld lct %ld\n", larg, haut, offset, p[offset], gct, lct);
//printf("img clair lg %lld, interlace:%ld\n", img.mLg, interlace);
long dx, dy, colind;
octet * q = img.ptr, * g, * h;
/* la bitmap en hexa fera une taille de larg*haut*3*2 */
dynInit(e, &gif, larg * haut * 3 * 2 + 1);
if(interlace)
{
dynInit(e, &entre, haut * 2 + 1);
short * ligent = (short *)entre.ptr, lig;
for(lig = 0; lig < (short)haut; lig += 8)
*ligent++ = lig;
for(lig = 4; lig < (short)haut; lig += 8)
*ligent++ = lig;
for(lig = 2; lig < (short)haut; lig += 4)
*ligent++ = lig;
for(lig = 1; lig < (short)haut; lig += 2)
*ligent++ = lig;
}
/* */
ind = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE) + 1;
dynStoreNumber(e, &ctxPdf->mImg, ind, 1, larg, cFM, cVM);
dynStoreNumber(e, &ctxPdf->mImg, ind, 2, haut, cFM, cVM);
dynConcatSz(e, &ctxPdf->mImg, sVM, 1);
// boucle sur chaque pixel
g = gif.ptr;
for(dy = 0; dy < haut; dy++)
{
if(interlace)
{
/* gerer l'entrelacement */
g = gif.ptr + ((short *)entre.ptr)[dy] * larg * 3 * 2;
}
/* */
for(dx = 0; dx < larg; dx++)
{
colind = (lct ? lct : gct) + (*q++) * 3;
/* */
h = (octet *)dynConvertCharToCharHexa(p[colind++]);
*g++ = *h++;
*g++ = *h++;
h = (octet *)dynConvertCharToCharHexa(p[colind++]);
*g++ = *h++;
*g++ = *h++;
h = (octet *)dynConvertCharToCharHexa(p[colind]);
*g++ = *h;
*g++ = *h;
}
}
dynSetLen(e, &gif, larg * haut * 3 * 2);
dynConcat(e, &ctxPdf->mImg, &gif);
dynFree(e, &gif);
if(interlace)
dynFree(e, &entre);
dynFree(e, &img);
/* verifs si d'autres images ? */
/* eventuellement a la fin, decoder les blocks possibles (GIF89a only) : comment extension, plaintext extension : remettre le bloc "while" ci dessus des extensions
enfin, verifier le dernier octet du fichier : doit etre '\x3B' (GIF terminator)
*/
return TRUE;
}
WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic * lignes, long format)
{
// enchaine automatiquement les fonctions pour creer un pdf de type "listing" (log ou programme)
// police Courrier taille 9 en A4 =>
// paysage : 60 lignes 145 colonnes
// portrait : 87 lignes 99 colonnes
long nbLigPage, nbColPage;
if(format == PDFFMT_A4P)
{
// portrait
nbLigPage = 87;
nbColPage = 99;
}
else if(format == PDFFMT_A4L)
{
// paysage (Landscape)
nbLigPage = 60;
nbColPage = 145;
}
else
return FALSE; // format non pris en charge
//
long nbPage, nbLig;
dynErase(e, lignes, "\r");
nbLig = dynDcount(e, lignes, 10, DYN_NONE, DYN_NONE); // \n
if(nbLig == 0)
nbPage = 1;
else
nbPage = (nbLig - 1) / nbLigPage + 1;
//
dynLet(e, &ctxPdf->mTmp3, "Courier", DYN_LGNONE);
if( ! newPdf(e, ctxPdf, titre, nbPage, format, &ctxPdf->mTmp3))
return FALSE;
//
long iPage, iLigPage, iLigTotal = 1;
for(iPage = 1; iPage <= nbPage; iPage++)
{
dynConcatSz(e, &ctxPdf->mPage, "BT /F1 9 Tf ", 12); // Fonte 1 = Courier (/F1)
fmt2(e, &ctxPdf->mPage, ctxPdf->mLmarg, ctxPdf->mHaut - ctxPdf->mHmarg);
dynConcatSz(e, &ctxPdf->mPage, " Td 9 TL\r\n", DYN_LGNONE);
//
for(iLigPage = 1; iLigPage <= nbLigPage && iLigTotal <= nbLig; iLigPage++)
{
dynField(e, lignes, &ctxPdf->mTmp1, iLigTotal++, DYN_NONE, 10, DYN_NONE, 1);
if(ctxPdf->mTmp1.mLg > nbColPage)
dynSetLen(e, &ctxPdf->mTmp1, nbColPage);
pdfEchap(e, &ctxPdf->mTmp2, &ctxPdf->mTmp1);
dynConcatSz(e, &ctxPdf->mPage, "(", 1);
dynConcatSz(e, &ctxPdf->mPage, ctxPdf->mTmp2.mPtr, ctxPdf->mTmp2.mLg);
dynConcatSz(e, &ctxPdf->mPage, ") '\r\n", DYN_LGNONE);
}
dynConcatSz(e, &ctxPdf->mPage, "ET\r\n", DYN_LGNONE);
//
if( ! setPdfPage(e, ctxPdf, 1)) // avec compression
return FALSE;
}
return endPdf(e, ctxPdf);
}
/* ******************************************************** */
+121 -93
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,9 +27,13 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#define RAND_STATE_COUNT 624
#define RAND_PERIOD 397
/* ============================================================================================= */
enum {
RAND_STATE_COUNT = 624,
RAND_PERIOD = 397
};
typedef struct {
int error; // dernier code erreur specifique au module
@@ -60,7 +64,7 @@ static void randomTwist(modEtat * etat)
etat->index = 0;
}
ent32 randomGenerate(modEtat * etat)
static ent32 randomGenerate(modEtat * etat)
{
if (etat->index >= RAND_STATE_COUNT)
randomTwist(etat);
@@ -73,130 +77,154 @@ ent32 randomGenerate(modEtat * etat)
return y & 0xFFFFFFFF;
}
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_NB = 0
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error" // 0
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
randomInit(p_etat, time(NULL));
//
}
}
else if(strncmp(e->fn, "end", 3) == 0)
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
exc = EX_MODPARAM; // bad type of parameter
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
randomInit(p_etat, time(NULL));
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "setSeed", 7) == 0)
else if(p_etat == NULL)
{
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
randomInit(p_etat, (ent32)((param1->num / NUM_FACTEUR) & 0xFFFFFFFF));
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "error", 5))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
param1->num = (((ent64)(randomGenerate(p_etat))) * NUM_FACTEUR);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else if(modFnIs(e, "setSeed", 7))
{
/* get param in the right order */
var * paramSeedValue = getParam(e, "seedValue", 9);
if(paramSeedValue == NULL)
exc = EX_MODPARAM;
else if(paramSeedValue->type != VAR_NUMBER && paramSeedValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number seed;
if(var_conv_num(e, paramSeedValue, &seed))
randomInit(p_etat, (ent32)((seed / NUM_FACTEUR) & 0xFFFFFFFF));
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
/* get param in the right order */
var * paramNextRandomNumber = getParam(e, "nextRandomNumber", 16);
if(paramNextRandomNumber == NULL)
exc = EX_MODPARAM;
else
{
if(paramNextRandomNumber->type != VAR_NUMBER)
var_let(e, paramNextRandomNumber, &e->int_number, FALSE, FALSE);
paramNextRandomNumber->num = (((ent64)(randomGenerate(p_etat))) * NUM_FACTEUR);
}
}
/* ============================================================================================= */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+100
View File
@@ -0,0 +1,100 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
// --- gestion protocole "raw"
typedef struct {
int state; /* etat de decodage des trames "raw" : 0 entete a lire, 1 lecture corps */
ent64s lengthToRead; /* longueur de donnees (corps) restant a lire */
Dynamic content; /* corps du message */
Dynamic line; /* variable de travail */
int error;
} modCtxRaw;
enum {
RAWSTATE_HEADERTOREAD = 0,
RAWSTATE_READINGCONTENT = 1,
/* erreurs */
RAW_ERROR_CONTENTLENGTH = 1,
/* codes retour */
RAW_REQUEST_INPROGRESS = 0,
RAW_REQUEST_COMPLETE = 1,
RAW_REQUEST_ERROR = -1
};
WAPIDECL void Init(env * e, modCtxRaw * ctx);
WAPIDECL void End(env * e, modCtxRaw * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxRaw * ctx, Dynamic * data);
WAPIDECL long MakeResponse(env * e, modCtxRaw * ctx, Dynamic * reponse);
/*
case FCGI_BEGIN_REQUEST:
// verif BEGIN_REQUEST recu : keep alive ?
mKeepAlive = (*(mDataOut.GetContentPtr() + 2) == 1);
// entre 4 Ko et 256 Ko
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) ; // erreur
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) ; // erreur
#include <netinet/tcp.h>
// Activer SO_KEEPALIVE
int yes = 1;
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes));
// Apres 30s d'inactivite, commencer les sondes
int idle = 30;
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle));
// Intervalle de 10s entre sondes
int interval = 10;
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval));
// 3 tentatives avant abandon
int maxpkt = 3;
setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt));
// sous windows, seuls les parametres temporels se font differemment :
// Parametrage keepalive
// Activer SO_KEEPALIVE
BOOL optval = TRUE;
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval));
struct tcp_keepalive keepalive;
keepalive.onoff = 1;
keepalive.keepalivetime = 30000; // 30 secondes avant 1ere sonde
keepalive.keepaliveinterval = 10000; // 10 secondes entre sondes
if (WSAIoctl(sock, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), NULL, 0, &bytesReturned, NULL, NULL) == SOCKET_ERROR)
printf("WSAIoctl failed: %d\n", WSAGetLastError());
// preco : prevoir un "heartbeat" applicatif
*/
+114
View File
@@ -0,0 +1,114 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "raw.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxRaw * ctx)
{
ctx->state = RAWSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
ctx->error = 0;
dynInit(e, &ctx->content, DYN_LGMIN);
dynInit(e, &ctx->line, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxRaw * ctx)
{
dynFree(e, &ctx->content);
dynFree(e, &ctx->line);
}
WAPIDECL long ExtractMessage(env * e, modCtxRaw * ctx, Dynamic * data)
{
if(ctx->state == RAWSTATE_HEADERTOREAD)
{
if(data->mLg < 8)
return RAW_REQUEST_INPROGRESS;
/* */
dynSubstr(e, data, &ctx->line, 0, 8, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, 8);
ctx->lengthToRead = dynToNum(e, &ctx->line, DYN_FALSE, 0);
if(ctx->line.mInternal == DYN_ERR)
{
ctx->error = RAW_ERROR_CONTENTLENGTH;
return RAW_REQUEST_ERROR;
}
ctx->error = 0;
if(ctx->lengthToRead == 0)
{
dynSetLen(e, &ctx->content, 0);
return RAW_REQUEST_COMPLETE;
}
ctx->state = RAWSTATE_READINGCONTENT;
}
if(ctx->state == RAWSTATE_READINGCONTENT)
{
// lecture corps
if(data->mLg < ctx->lengthToRead)
{
/* partiel */
dynConcat(e, &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return RAW_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees dispo */
dynConcatSz(e, &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
ctx->lengthToRead = 0;
ctx->state = RAWSTATE_HEADERTOREAD;
return RAW_REQUEST_COMPLETE;
}
}
return RAW_REQUEST_ERROR;
}
WAPIDECL long MakeResponse(env * e, modCtxRaw * ctx, Dynamic * reponse)
{
/* ajouter la longueur en debut de reponse */
long lg = reponse->mLg;
dynInsSz(e, reponse, 1, DYN_NONE, "0000000", 7, '0', DYN_NONE);
/* formater la longueur 00000000 */
dynFmtNumber(e, (ent64s)lg, &ctx->line, 'R', '0', 8);
strncpy(reponse->mPtr, ctx->line.mPtr, 8);
/* */
return OK;
}
+156 -112
View File
@@ -26,17 +26,56 @@
// TODO version windows
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/types.h>
#else
#include "windows.h" // pour les fonctions FindFile...
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
#include "dynamic.h"
#include "rep.h"
long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount)
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ******** PRIVATE ********************* */
static int GetInclude(env * e, Dynamic * line, Dynamic * includeFilename)
{
// check that the <line> is a include w statement. If not, return zero, else
// return in <includeFilename> the name of the include file
// separators are 9 and 32 (tab and space) and ";"" for the optional end of line comment
char * p = line->mPtr, * q;
while(*p && (*p == 9 || *p == 32)) p++;
if(*p++ != 'i') return 0;
if(*p++ != 'n') return 0;
if(*p++ != 'c') return 0;
if(*p++ != 'l') return 0;
if(*p++ != 'u') return 0;
if(*p++ != 'd') return 0;
if(*p++ != 'e') return 0;
if(*p != 9 && *p != 32) return 0;
p++;
while(*p && (*p == 9 || *p == 32)) p++;
if(*p != '\'' && *p != '"') return 0;
q = p + 1; // *p is the first char of include filename , including ' or ", and that chra must bi found at the end of the file
while(*q && (*q != *p)) q++;
if(*q != *p) return 0; // *q must be the same ' or " that begins filename
long lg = q - p - 1;
if(lg < 1) return 0;
dynLet(e, includeFilename, p + 1, lg);
dynSetLen(e, includeFilename, lg); // to be sure that \0 ends the filename
return 1;
}
/* ******** PUBLIC ********************* */
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount)
{
if(!e || !directory || !fileFound || !fileFoundCount || !duplicateCount)
return 0; // error
@@ -81,9 +120,10 @@ long ScanDirectory(env * e, const char * path, Dynamic * directory, const char *
#ifdef UNIX
if((dir = opendir(workPath.mPtr)) == NULL)
{
// TODO ?! exit or continue to next item ?
dynFree(e, &workPath);
return 0;
// continue to next item (no access right for example for this directory, etc.)
//dynFree(e, &workPath);
//return 0;
continue;
}
while ((entry = readdir(dir)) != NULL)
{
@@ -129,9 +169,10 @@ long ScanDirectory(env * e, const char * path, Dynamic * directory, const char *
dynConcatSz(e, &workPath, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(workPath.mPtr, &FindFileData)) == INVALID_HANDLE_VALUE)
{
// TODO ?! exit or continue to next item ?
dynFree(e, &workPath);
return 0;
// continue to next item (no access right for example for this directory, etc.)
//dynFree(e, &workPath);
//return 0;
continue;
}
dynSetLen(e, &workPath, workPath.mLg - 2); // enlever \* mis a la fin...
for(int cr = -1;cr != 0;)
@@ -188,62 +229,47 @@ long ScanDirectory(env * e, const char * path, Dynamic * directory, const char *
return 1;
}
static int GetInclude(env * e, Dynamic * line, Dynamic * includeFilename)
{
// check that the <line> is a include w statement. If not, return zero, else
// return in <includeFilename> the name of the include file
// separators are 9 and 32 (tab and space) and ";"" for the optional end of line comment
char * p = line->mPtr, * q;
while(*p && (*p == 9 || *p == 32)) p++;
if(*p++ != 'i') return 0;
if(*p++ != 'n') return 0;
if(*p++ != 'c') return 0;
if(*p++ != 'l') return 0;
if(*p++ != 'u') return 0;
if(*p++ != 'd') return 0;
if(*p++ != 'e') return 0;
if(*p != 9 && *p != 32) return 0;
p++;
while(*p && (*p == 9 || *p == 32)) p++;
q = p; // *p is the first char of include filename (except if *p is null)
while(*q && (*q != 9 && *q != 32 && *q != ';')) q++;
// *q is the last char of include filename
if( (! *p) || *p == ';') return 0;
if(*q == ';') q--;
// find it : copy do includeFilename
long lg = q - p + 1;
dynLet(e, includeFilename, p, lg);
dynSetLen(e, includeFilename, lg); // to be sure that \0 ends the filename
dynErase(e, includeFilename, "'\"");
return 1;
}
long GetSource(env * e, const char * wsrc, const char * filename, Dynamic * source, Dynamic * meta)
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta)
{
int cr = 0;
char cLF = 10;
char sLF[2] = {"\n"};
char sCR[2] = {"\r"};
dynSetLen(e, source, 0);
dynSetLen(e, meta, 0);
//
Dynamic directory, fileFound, line, include, tmp;
dynInit(e, &directory, DYN_LGMIN);
Dynamic fileFound, line, include, filenameFound;
dynInit(e, &fileFound, DYN_LGMIN);
dynInit(e, &line, DYN_LGMIN);
dynInit(e, &include, DYN_LGMIN);
dynInit(e, &tmp, DYN_LGMIN);
dynInit(e, &filenameFound, DYN_LGMIN);
//
long fileCount, dup;
for(;;)
{
if(dynRead(e, source, (char *)filename) != DYN_OK)
if( ScanDirectory(e, NULL, directory, filename, &fileFound, &fileCount, &dup) != 1)
{
cr = 1;
break;
if( ! ScanDirectory(e, wsrc, &directory, NULL, &fileFound, &fileCount, &dup))
}
if(fileCount != 1)
{
cr = 2;
break;
}
if(dynRead(e, source, fileFound.mPtr) != DYN_OK)
{
cr = 3;
break;
}
dynErase(e, source, sCR);
//
long level = 1, current = 1;
dynStoreSz(e, meta, 1, DYN_NONE, "00000001", 8, cFM, DYN_NONE);
dynStoreSz(e, meta, 2, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
dynStoreSz(e, meta, 3, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
long treeLevel = 1, currentLevel = 1, level = 0, nbMeta = 1;
dynStoreSz(e, meta, META_GLOBAL_LN, DYN_NONE, "00000001", 8, cFM, DYN_NONE);
dynStoreSz(e, meta, META_FILENAME, DYN_NONE, fileFound.mPtr, DYN_LGNONE, cFM, DYN_NONE);
dynStoreSz(e, meta, META_LOCAL_LN, DYN_NONE, "1", DYN_LGNONE, cFM, DYN_NONE);
dynStoreNumber(e, meta, META_LEVEL, DYN_NONE, currentLevel, cFM, DYN_NONE);
dynStoreSz(e, meta, META_FILETREE, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
// foreach source line
long numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE);
long numLine = 1;
@@ -253,99 +279,117 @@ long GetSource(env * e, const char * wsrc, const char * filename, Dynamic * sour
numLine++;
if(GetInclude(e, &line, &include))
{
//printf("include: %s\n", include.mPtr);
if(ScanDirectory(e, NULL, &directory, include.mPtr, &fileFound, &fileCount, &dup))
if(ScanDirectory(e, NULL, directory, include.mPtr, &fileFound, &fileCount, &dup))
{
//printf("nb found %ld: %s\n", fileCount, fileFound.mPtr);
if(fileCount == 1)
{
// memo include file tree to avoid cyclic includes and get meta data
// 2 memos : one for call tree, and one for the map of files/number of lines
// call tree =>
// meta<3> = file tree, multi-valued filenames
// meta<5> = file tree, multi-valued filenames (temporary, during GetSource)
// meta data =>
// meta<1> = beginning number of line
// meta<1> = beginning line number, global
// meta<2> = filename
// meta<3> = local line number
// meta<4> = level
//
// if filename already presents in file tree, error (ignore include)
if(dynLocateSz(e, meta, fileFound.mPtr, cVM, 3, cFM) > 0)
continue;
// insert include file after include's line
dynRead(e, &include, fileFound.mPtr);
if(include.mLg == 0)
continue; // don't insert empty file
// suppress last character if LF : prevent blank line in result
if(include.mPtr[include.mLg - 1] == cLF)
dynSetLen(e, &include, include.mLg - 1);
//
// TODO : insert ENDINCLUDE pseudo code at the end of inserted include ? or only when generating pcode ! see with assembler.c
dynIns(e, source, numLine, DYN_NONE, &include, cLF, DYN_NONE);
long nbInclude = dynDcount(e, &include, cLF, DYN_NONE, DYN_NONE);
numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE);
//printf("inc ok %s nbinclude %ld nbline %ld current %ld\n", fileFound.mPtr, nbInclude, numberOfLines, numLine);
// put in <include> the line number formatted 00000000 and split current block in three
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
long pos = abs(dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, 1, cFM));
dynIns(e, meta, 1, pos, &include, cFM, cVM);
dynIns(e, meta, 2, pos, &fileFound, cFM, cVM);
//
//dynExtractSubField(e, meta, 2, pos - 1, &include); // ko si separateurs changent...
dynField(e, meta, &include, 2, pos - 1, cFM, cVM, 1);
dynIns(e, meta, 2, pos + 1, &include, cFM, cVM);
dynFmtNumber(e, numLine + nbInclude, &include, 'R', '0', 8);
dynIns(e, meta, 1, pos + 1, &include, cFM, cVM);
//
// adjust starting line of next blocks
long nbMeta = dynDcount(e, meta, cVM, 2, cFM);
for(long cpt = pos + 2; cpt <= nbMeta; cpt++)
dynField(e, &fileFound, &filenameFound, dynDcount(e, &fileFound, e->path_sep[0], DYN_NONE, DYN_NONE), DYN_NONE, e->path_sep[0], DYN_NONE, 1); // extract filename from full path
if(dynLocateSz(e, meta, filenameFound.mPtr, cVM, META_FILETREE, cFM) > 0)
{
//long num = dynExtractSubFieldAsNumber(e, meta, 1, cpt, &include) + nbInclude;
long num = dynFieldAsNumber(e, meta, 1, cpt, cFM, cVM) + nbInclude;
dynFmtNumber(e, num, &include, 'R', '0', 8);
dynStore(e, meta, 1, cpt, &include, cFM, cVM);
cr = 4;
break;
}
// insert include file after include's line
if(include.mLg == 0) // don't insert empty file (else, local line number calculus wouldn't be correct), add one space instead
{
dynLet(e, &include, " ", 1);
}
else
{
dynErase(e, &include, sCR);
if(include.mPtr[include.mLg - 1] != cLF)
dynConcatSz(e, &include, sLF, 1); // add empty final line if there's not, else meta would have double same global line (if last line is include's line)
}
//
dynStore(e, meta, 3, ++level, &fileFound, cFM, cVM);
current++;
dynIns(e, source, numLine, DYN_NONE, &include, cLF, DYN_NONE);
long nbInclude = dynDcount(e, &include, cLF, DYN_NONE, DYN_NONE);
numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE); // extending scope
//
// put in <include> the line number formatted 00000000 and split current block in three
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
long pos = abs(dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM));
dynIns(e, meta, META_GLOBAL_LN, pos, &include, cFM, cVM);
dynIns(e, meta, META_FILENAME, pos, &fileFound, cFM, cVM);
dynInsSz(e, meta, META_LOCAL_LN, pos, "1", 1, cFM, cVM);
level = dynFieldAsNumber(e, meta, META_LEVEL, pos - 1, cFM, cVM);
dynInsNumber(e, meta, META_LEVEL, pos, level + 1, cFM, cVM);
currentLevel = level + 1;
//
dynField(e, meta, &include, 2, pos - 1, cFM, cVM, 1);
dynIns(e, meta, META_FILENAME, pos + 1, &include, cFM, cVM);
dynFmtNumber(e, numLine + nbInclude, &include, 'R', '0', 8);
dynIns(e, meta, META_GLOBAL_LN, pos + 1, &include, cFM, cVM);
long global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, pos - 1, cFM, cVM);
long local = dynFieldAsNumber(e, meta, META_LOCAL_LN, pos - 1, cFM, cVM);
dynInsNumber(e, meta, META_LOCAL_LN, pos + 1, numLine - global + local, cFM, cVM);
dynInsNumber(e, meta, META_LEVEL, pos + 1, level, cFM, cVM);
//
// adjust starting line of next blocks
nbMeta = dynDcount(e, meta, cVM, META_FILENAME, cFM);
for(long cpt = pos + 2; cpt <= nbMeta; cpt++)
{
global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, cpt, cFM, cVM);
dynFmtNumber(e, global + nbInclude, &include, 'R', '0', 8);
dynStore(e, meta, META_GLOBAL_LN, cpt, &include, cFM, cVM);
}
//
dynStore(e, meta, META_FILETREE, ++treeLevel, &filenameFound, cFM, cVM);
}
else
{
cr = 5; // if fileCount <> 1, error (multiple included include not autorized, or not found when filename includes dot or path separator char)
break;
}
// if fileCount > 1, error (ignore include)
}
// if error while searching for the include file, error (ignore include)
else
{
cr = 6; // if error while searching for the include file, error
break;
}
}
// delete last file in call tree when changing of file
// dynSetAsNumber(e, &tmp, numLine);
//dynFmt(e, &tmp, &include, 'R', '0', 8); // TODO dynFmtNumber
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
long pos = dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, 1, cFM);
if(pos != current && level > 0)
{
current = pos;
dynDel(e, meta, 3, level--, cFM, cVM, 1);
}
long pos = dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM);
if(pos < 0)
pos = abs(pos) - 1;
if(pos > nbMeta)
pos = nbMeta;
level = dynFieldAsNumber(e, meta, META_LEVEL, pos, cFM, cVM);
if(level < currentLevel)
dynDel(e, meta, META_FILETREE, treeLevel--, cFM, cVM, 1);
currentLevel = level;
}
dynDel(e, meta, 3, DYN_NONE, cFM, DYN_NONE, 1);
cr = 1;
dynDel(e, meta, META_FILETREE, DYN_NONE, cFM, DYN_NONE, 1);
break;
}
//
dynFree(e, &directory);
dynFree(e, &fileFound);
dynFree(e, &line);
dynFree(e, &include);
dynFree(e, &tmp);
dynFree(e, &filenameFound);
return cr;
}
void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound)
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine)
{
indice *= 2;
indice = (indice - 1) * META_NB;
dynFmtNumber(e, lineNumber, fileFound, 'R', '0', 8);
long pos = dynSortLocateSz(e, meta, fileFound->mPtr, cVM, DYN_SORT_ASC, indice - 1, cFM);
long pos = dynSortLocateSz(e, meta, fileFound->mPtr, cVM, DYN_SORT_ASC, indice + META_GLOBAL_LN, cFM);
if(pos < 0)
{
pos = abs(pos) - 1;
if(pos < 1) pos = 1; // securite
}
dynSetLen(e, fileFound, 0);
dynField(e, meta, fileFound, indice, pos, cFM, cVM, 1);
//
*ficLine = lineNumber - dynFieldAsNumber(e, meta, indice + META_GLOBAL_LN, pos, cFM, cVM) + dynFieldAsNumber(e, meta, indice + META_LOCAL_LN, pos, cFM, cVM);
dynField(e, meta, fileFound, indice + META_FILENAME, pos, cFM, cVM, 1);
}
+15 -3
View File
@@ -23,10 +23,22 @@
#ifndef REP_H
#define REP_H
long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount);
long GetSource(env * e, const char * wsrc, const char * filename, Dynamic * source, Dynamic * meta);
#include "apidecl.h"
void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound);
enum {
META_GLOBAL_LN = 1,
META_FILENAME = 2,
META_LOCAL_LN = 3,
META_LEVEL = 4,
META_FILETREE = 5,
META_WSRC = 5,
META_NB = 5
};
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount);
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta);
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine);
/* ********************************************** */
#endif
+63
View File
@@ -0,0 +1,63 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "sock.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
/* codes a passer a la fonction setError */
enum {
WSECURESOCKET_CACERT = -6, /* genere lors de l'init, chargement certificats de confiance */
WSECURESOCKET_WANTREAD = -5,
WSECURESOCKET_WANTWRITE = -4,
WSECURESOCKET_SSLERROR = -3,
WSECURESOCKET_MEM_ERROR = -2,
WSECURESOCKET_ERROR = -1,
WSECURESOCKET_OK = 0,
};
typedef struct {
modContextSocket ctxSock;
SSL_CTX * clientSecureCtx;
SSL_CTX * serverSecureCtx;
SSL * sslServer;
SSL * sslClient;
Dynamic sslList; /* <1> = Socket ascii en MV, <2> = SSL * ent64s ascii en MV lie */
int packet; /* taille des paquets en lecture */
Dynamic lastError; /* derniere erreur : derniere opération SSL, init module */
} modContextSecureSocket;
WAPIDECL int initSecureSock(env * e, modContextSecureSocket * ctx);
WAPIDECL void freeSecureSock(env * e, modContextSecureSocket * ctx);
WAPIDECL void freeOneSecureSock(env * e, modContextSecureSocket * ctx, Socket sock);
WAPIDECL void DelSslServeur(env * e, modContextSecureSocket * ctx);
WAPIDECL long SetPemCertificate(env * e, modContextSecureSocket * ctx, Dynamic * cert, Dynamic * key);
WAPIDECL long SetCACertificate(env * e, modContextSecureSocket * ctx, Dynamic * cacert);
WAPIDECL long SecureSocketServer(env * e, modContextSecureSocket * ctx, Socket sock, long timeoutMs); /* secure socket from server accept */
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server, long timeoutMs);
WAPIDECL long ReadSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs);
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs);
+443
View File
@@ -0,0 +1,443 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#ifdef UNIX
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#else
#include "winsock2.h"
#include "windows.h"
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "securesock.h"
typedef struct {
int error; /* dernier code erreur specifique au module */
//***
modContextSecureSocket ctxSecureSock;
} modEtat;
#define MOD_VERSION 1
enum {
EXMOD_SECURESOCK_SERVER_PORT_INVALID = 1,
EXMOD_SECURESOCK_NEW = 2,
EXMOD_SECURESOCK_SETSERVER = 3,
EXMOD_SECURESOCK_CONNECT = 4,
EXMOD_SECURESOCK_WAIT = 5,
EXMOD_SECURESOCK_ACCEPT = 6,
EXMOD_SECURESOCK_READ = 7,
EXMOD_SECURESOCK_WRITE = 8,
EXMOD_SECURESOCK_SECURESERVER = 9,
EXMOD_SECURESOCK_SECURECLIENT = 10,
EXMOD_SECURESOCK_SETCERTIFICATE = 11,
EXMOD_SECURESOCK_NOTNUM = 12,
EXMOD_NB = 12
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Port number invalid",
"New socket error",
"Listen socket on port error",
"Connect socket error",
"Waiting for socket error", // 5
"Accept socket error",
"Read socket error",
"Write socket error",
"Secure server socket error",
"Secure client socket error", // 10
"Certificate error",
"Socket expected as number"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
p_etat->error = initSecureSock(e, &p_etat->ctxSecureSock);
/* ne pas lever une exception, juste l'erreur => 1er appel est securesock&error() pour verifier que l'init (automatique) s'est bien passe (ou methode pour charger les cacert !?) */
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
freeSecureSock(e, &p_etat->ctxSecureSock);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "server", 6))
{
/* get param in the right order */
var * paramPortNumber = getParam(e, "portNumber", 10);
var * paramCertificate = getParam(e, "certificate", 11);
var * paramPrivateKey = getParam(e, "privateKey", 10);
if(paramPortNumber == NULL || paramCertificate == NULL || paramPrivateKey == NULL)
exc = EX_MODPARAM;
else if((paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC) ||
paramCertificate->type != VAR_DYNAMIC || paramPrivateKey->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* cree un point d'entree serveur securise SSL/TLS */
number port;
if( ! var_conv_num(e, paramPortNumber, &port))
exc = EX_MODPARAM;
else if(port < 1024 * NUM_FACTEUR || port > 65535 * NUM_FACTEUR)
exc = setError(p_etat, EXMOD_SECURESOCK_SERVER_PORT_INVALID); /* en dessous de 1024, necessite des autorisations speciales, non gere ici */
else
{
if(NewSocket(e, &p_etat->ctxSecureSock.ctxSock) == WSOCKET_OK)
{
if(SocketSetServer(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.sock, (int)(port / NUM_FACTEUR)) == WSOCKET_OK)
{
if(SetPemCertificate(e, &p_etat->ctxSecureSock, paramCertificate, paramPrivateKey) == WSECURESOCKET_OK)
{
exc = OK; /* un seul serveur en ecoute ! */
}
else
exc = setError(p_etat, EXMOD_SECURESOCK_SETCERTIFICATE);
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_SETSERVER);
}
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_NEW);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "connect", 7))
{
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramPortNumber = getParam(e, "portNumber", 10);
var * paramSocket = getParam(e, "socket", 6);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramHost == NULL || paramPortNumber == NULL || paramSocket == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramHost->type != VAR_DYNAMIC || (paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC) || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
/* connexion a un serveur securise SSL/TLS */
number port, timeout;
if( ! var_conv_num(e, paramPortNumber, &port) && var_conv_num(e, paramTimeout, &timeout))
exc = EX_MODPARAM;
else
{
if(NewSocket(e, &p_etat->ctxSecureSock.ctxSock) == WSOCKET_OK)
{
if(SocketConnectToServer(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.sock, (int)(port / NUM_FACTEUR), paramHost) == WSOCKET_OK)
{
if(SecureSocketClient(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock, paramHost, timeout * 1000 / NUM_FACTEUR) == WSECURESOCKET_OK)
{
if(paramSocket->type != VAR_NUMBER)
var_let(e, paramSocket, &e->int_number, FALSE, FALSE);
paramSocket->num = p_etat->ctxSecureSock.ctxSock.sock; /* TODO tableau de connexion cliente (SSL*) */
exc = OK;
}
else
{
freeOneSecureSock(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock);
exc = setError(p_etat, EXMOD_SECURESOCK_SECURECLIENT);
}
}
else
{
/* pas de FreeSocket a faire ici */
exc = setError(p_etat, EXMOD_SECURESOCK_CONNECT);
}
}
else
{
/* pas de FreeSocket a faire ici */
exc = setError(p_etat, EXMOD_SECURESOCK_NEW);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "setCACert", 9))
{
/* get param in the right order */
var * paramCert = getParam(e, "certFile", 8);
if(paramCert == NULL)
exc = EX_MODPARAM; /* erreur */
else if(paramCert->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
else
{
exc = setError(p_etat, SetCACertificate(e, &p_etat->ctxSecureSock, paramCert));
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stopServer", 10))
{
/* supprime tous les ssl de type serveur et les supprime de la liste */
DelSslServeur(e, &p_etat->ctxSecureSock);
/* supprime le serveur en ecoute */
FreeSocket(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock);
p_etat->ctxSecureSock.ctxSock.servSock = INVALID_SOCKET;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stop", 4))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
if(paramSocket == NULL)
exc = EX_MODPARAM;
else if(paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* arret connexion */
number socket;
if( var_conv_num(e, paramSocket, &socket) )
freeOneSecureSock(e, &p_etat->ctxSecureSock, socket);
else
exc = setError(p_etat, EXMOD_SECURESOCK_NOTNUM);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "wait", 4))
{
/* get param in the right order */
var * paramTimeout = getParam(e, "timeout", 7);
var * paramClientSock = getParam(e, "clientSock", 10);
if(paramTimeout == NULL || paramClientSock == NULL)
exc = EX_MODPARAM;
else if(paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if( ! var_conv_num(e, paramTimeout, &timeout) )
exc = EX_MODPARAM;
else
{
if(paramClientSock->type != VAR_NUMBER)
var_let(e, paramClientSock, &e->int_number, FALSE, FALSE);
/* attend une nouvelle connexion entrante */
long cr = WaitOneSocketForRead(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock, timeout * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SECURESOCK_WAIT);
else if(cr == 0)
paramClientSock->num = NUM_MOINSUN; /* => timeout, RAS */
else
{
if(AcceptClientSocket(e, &p_etat->ctxSecureSock.ctxSock) == WSOCKET_OK)
{
if(SecureSocketServer(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock, timeout * 1000 / NUM_FACTEUR) == WSECURESOCKET_OK)
{
paramClientSock->num = p_etat->ctxSecureSock.ctxSock.sock; /* nouvelle connexion cliente securisee */
exc = OK;
}
else
{
freeOneSecureSock(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock);
exc = setError(p_etat, EXMOD_SECURESOCK_SECURESERVER);
}
}
else
exc = setError(p_etat, EXMOD_SECURESOCK_ACCEPT);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
else
{
/* lire par paquets de longueur fixe et s'arreter des que plus rien a lire, lecture par paquets de <pas> octets */
number socket, timeout;
if( var_conv_num(e, paramSocket, &socket) && var_conv_num(e, paramTimeout, &timeout) )
{
if(paramData->type != VAR_DYNAMIC)
{
var_let(e, paramData, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramData, 0);
}
/* lecture sur la connexion : lecture par paquets de longueur fixe et s'arreter des que plus rien a lire */
if(ReadSecureSocket(e, &p_etat->ctxSecureSock, socket, paramData, timeout * 1000 / NUM_FACTEUR) != WSOCKET_OK)
{
/* si erreur d'E/S, arreter tout */
freeOneSecureSock(e, &p_etat->ctxSecureSock, socket);
exc = setError(p_etat, EXMOD_SECURESOCK_READ);
}
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
else
{
number socket, timeout;
if( var_conv_num(e, paramSocket, &socket) && var_conv_num(e, paramTimeout, &timeout) )
{
/* ecriture sur la connexion : : pbm une seule socket geree ici !! */
if(WriteSecureSocket(e, &p_etat->ctxSecureSock, socket, paramData, timeout * 1000 / NUM_FACTEUR) != WSOCKET_OK)
{
/* si erreur d'E/S, arreter tout */
freeOneSecureSock(e, &p_etat->ctxSecureSock, socket);
exc = setError(p_etat, EXMOD_SECURESOCK_WRITE);
}
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+434
View File
@@ -0,0 +1,434 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "securesock.h"
#include <openssl/x509v3.h>
//#include "dynamic.h"
//#include <errno.h>
//#include <fcntl.h>
#ifdef WINLIB
#include <ws2tcpip.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/*
unix : -lssh -lcrypto -lssl -lz (dependances openssl zlib, verification avec : ldd /usr/lib/libssh.so)
sudo apt update
sudo apt install -y \
openssl libssl-dev \
zlib1g zlib1g-dev \
libssh-dev
openssl → binaire en ligne de commande
libssl-dev → headers + librairies pour compiler en C
zlib1g → runtime
zlib1g-dev → headers (zlib.h) + .so
libssh-dev → headers et libs de développement
windows : libssh.lib (et libssh compile avec msvc sinon ko)
ajouter => libssl.lib libcrypto.lib zlib.lib ws2_32.lib (car dependances openssl, zlib, socket)
git clone https://github.com/microsoft/vcpkg
cd vcpkg
bootstrap-vcpkg.bat
vcpkg install libssh:x64-windows
vcpkg install zlib:x64-windows
vcpkg install openssl:x64-windows
+ compil/link => cl main.c /I"path\to\vcpkg\installed\x64-windows\include" /link /LIBPATH:"path\to\vcpkg\installed\x64-windows\lib" libssh.lib libssl.lib libcrypto.lib zlib.lib ws2_32.lib
=> repertoire ou se trouve vcpkg (install depuis git) :
C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows
À l'exécution il faut :
libssl-*.dll
libcrypto-*.dll
dans :
même dossier que .exe ou dans le PATH
=== CERTIFICAT auto signé
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
avec windows, c'est pareil, sauf initsocket WAStartup, type SOCKET et pas int, closesocket() et il faut fournir un fichier ca (https://curl.se/ca/cacert.pem) pour la verification des certificats
https://kb.firedaemon.com/...openssl-binary-distributions : binaires openssl sous windows (3.5.6 LTS ok), ok avec libssh 0.12.x (eventuellement 0.11.x)
*/
/* ****** PRIVATE ************************ */
/*
SSL_ERROR_NONE = 0
SSL_ERROR_SSL = 1
SSL_ERROR_WANT_READ = 2
SSL_ERROR_WANT_WRITE = 3
SSL_ERROR_WANT_X509_LOOKUP = 4
SSL_ERROR_SYSCALL = 5
SSL_ERROR_ZERO_RETURN = 6
*/
static int processSSLresponse(env * e, modContextSecureSocket * ctx, SSL * ssl, int ret)
{
dynSetLen(e, &ctx->lastError, 0);
if(ret > 0)
return ret;
int ssl_err = SSL_get_error(ssl, ret);
if(ssl_err == SSL_ERROR_WANT_READ)
return WSECURESOCKET_WANTREAD;
if(ssl_err == SSL_ERROR_WANT_WRITE)
return WSECURESOCKET_WANTWRITE;
if (ssl_err == SSL_ERROR_ZERO_RETURN)
return 0; /* normalement faire SSL_Free + close socket (arrêt propre du pair) */
/* */
ERR_error_string_n(ERR_get_error(), ctx->lastError.mPtr, ctx->lastError.mLgmax);
return WSECURESOCKET_SSLERROR;
}
int verify_callback(int preverify_ok, X509_STORE_CTX * ctx) {
if (!preverify_ok) {
//int err = X509_STORE_CTX_get_error(ctx);
//int depth = X509_STORE_CTX_get_error_depth(ctx);
//printf("Échec de vérification à la profondeur %d : %s (code: %d)\n", depth, X509_verify_cert_error_string(err), err);
}
return preverify_ok;
}
static void AddSsl(env * e, modContextSecureSocket * ctx, SSL * ssl, Socket sock)
{
long pos = dynLocateSz(e, &ctx->sslList, Int64ToSz(e, (ent64s)sock, FALSE, 0), DYN_LGNONE, 1, cFM);
if(pos < 1)
{
dynInsNumber(e, &ctx->sslList, 1, 1, (ent64s)sock, cFM, cVM);
dynInsNumber(e, &ctx->sslList, 2, 1, (ent64s)ssl, cFM, cVM);
}
/* ne rien faire si deja existant */
}
static void DelSsl(env * e, modContextSecureSocket * ctx, Socket sock, int freeSsl)
{
long pos = dynLocateSz(e, &ctx->sslList, Int64ToSz(e, (ent64s)sock, FALSE, 0), DYN_LGNONE, 1, cFM);
if(pos > 0)
{
dynDel(e, &ctx->sslList, 1, pos, cFM, cVM, 1);
if(freeSsl)
SSL_free((SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM));
dynDel(e, &ctx->sslList, 2, pos, cFM, cVM, 1);
}
}
static void FreeSsl(env * e, modContextSecureSocket * ctx)
{
long nbSsl = dynDcount(e, &ctx->sslList, cVM, 1, cFM);
for(long pos = 1; pos <= nbSsl; pos++)
SSL_free((SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM));
/* SSL_shutdown(ssl) ? */
}
static SSL * GetSsl(env * e, modContextSecureSocket * ctx, Socket sock)
{
long pos = dynLocateSz(e, &ctx->sslList, Int64ToSz(e, (ent64s)sock, FALSE, 0), DYN_LGNONE, 1, cFM);
if(pos < 1)
return NULL;
else
return (SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
}
void debugSsl(env * e, modContextSecureSocket * ctx)
{
int nbSsl = dynDcount(e, &ctx->sslList, cVM, 1, cFM);
for(int pos = 1; pos <= nbSsl; pos++)
{
Socket sock = (Socket)dynFieldAsNumber(e, &ctx->sslList, 1, pos, cFM, cVM);
SSL * ssl = (SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
printf("SocketSSL[%d]=%d SSL %p / %s\n", pos, (int)sock, ssl, SSL_is_server(ssl) ? "serveur" : "client");
}
if(!nbSsl)
printf("SocketSSL empty!\n");
}
/* ****** PUBLIC ************************ */
WAPIDECL int initSecureSock(env * e, modContextSecureSocket * ctx)
{
int cr = OK;
initSock(e, &ctx->ctxSock);
/* */
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
/* */
dynInit(e, &ctx->lastError, DYN_LGMIN);
dynInit(e, &ctx->sslList, DYN_LGMIN);
/* */
ctx->packet = 64000; /* modifiable via methode a creer !? */
/* */
/* Partage un SSL_CTX si les connexions ont la même politique TLS. Crée plusieurs SSL_CTX si elles doivent avoir des politiques/configurations TLS différentes. !! */
ctx->clientSecureCtx = SSL_CTX_new(TLS_client_method());
/* */
/* Charger les autorités de confiance / appeler setCACert pour changer de cacert (test avec autosigne: appel setCACert avec le certificat serveur autosigne et le charger dans le client) */
if(SSL_CTX_set_default_verify_paths(ctx->clientSecureCtx) != 1) /* defaut linux : /etc/ssl/certs/ca-certificates.crt */
{
dynLet(e, &ctx->lastError, "error default load verify\n", DYN_LGNONE);
cr = WSECURESOCKET_CACERT;
}
/* Activer la vérification */
SSL_CTX_set_verify(ctx->clientSecureCtx, SSL_VERIFY_PEER, verify_callback); /* si dernier param = NULL, pas de verification */
/* */
ctx->serverSecureCtx = SSL_CTX_new(TLS_server_method());
/* SSL_CTX_load_verify_locations a faire sur ctxServeur si mTLS : authentification du serveur par le client (reciproque), sinon pas besoin */
/* */
return cr;
}
WAPIDECL void freeSecureSock(env * e, modContextSecureSocket * ctx)
{
FreeSsl(e, ctx); /* TODO array */
/* */
SSL_CTX_free(ctx->clientSecureCtx);
SSL_CTX_free(ctx->serverSecureCtx);
/* */
dynFree(e, &ctx->lastError);
dynFree(e, &ctx->sslList);
/* */
freeSock(e, &ctx->ctxSock);
}
WAPIDECL void freeOneSecureSock(env * e, modContextSecureSocket * ctx, Socket sock)
{
/* libere le contexte SSL et le supprime de la liste */
DelSsl(e, ctx, sock, TRUE);
/* ferme la socket et la supprime de la liste */
FreeSocket(e, &ctx->ctxSock, sock);
}
WAPIDECL void DelSslServeur(env * e, modContextSecureSocket * ctx)
{
long nbSsl = dynDcount(e, &ctx->sslList, cVM, 1, cFM);
for(long pos = nbSsl; pos > 0; pos--)
{
/* partir de la fin pour que les dynDel fonctionnent correctement */
SSL * ssl = (SSL *)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
if(SSL_is_server(ssl))
{
SSL_free(ssl);
Socket sock = (Socket)dynFieldAsNumber(e, &ctx->sslList, 2, pos, cFM, cVM);
FreeSocket(e, &ctx->ctxSock, sock);
/* */
dynDel(e, &ctx->sslList, 1, pos, cFM, cVM, 1);
dynDel(e, &ctx->sslList, 2, pos, cFM, cVM, 1);
}
}
}
WAPIDECL long SetCACertificate(env * e, modContextSecureSocket * ctx, Dynamic * cacert)
{
if (!SSL_CTX_load_verify_locations(ctx->clientSecureCtx, cacert->mPtr, NULL))
return WSECURESOCKET_CACERT;
else
return WSECURESOCKET_OK;
}
WAPIDECL long SetPemCertificate(env * e, modContextSecureSocket * ctx, Dynamic * cert, Dynamic * key)
{
if(SSL_CTX_use_certificate_file(ctx->serverSecureCtx, cert->mPtr, SSL_FILETYPE_PEM) <= 0)
return WSECURESOCKET_ERROR;
if(SSL_CTX_use_PrivateKey_file(ctx->serverSecureCtx, key->mPtr, SSL_FILETYPE_PEM) <= 0)
return WSECURESOCKET_ERROR;
return WSECURESOCKET_OK;
}
WAPIDECL long SecureSocketServer(env * e, modContextSecureSocket * ctx, Socket sock, long timeoutMs)
{
/* secure socket from server accept */
SetBlocking(sock, WSOCKET_NONBLOCKING);
ctx->sslServer = SSL_new(ctx->serverSecureCtx);
SSL_set_fd(ctx->sslServer, sock);
AddSsl(e, ctx, ctx->sslServer, sock); /* TODO array */
/* */
int ret;
for(;;)
{
if((ret = processSSLresponse(e, ctx, ctx->sslServer, SSL_accept(ctx->sslServer))) < 0)
{
if(ret == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, sock, timeoutMs);
if(cr > 0)
continue; /* donnees ok */
}
if(ret == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, sock, timeoutMs);
if(cr > 0)
continue; /* donnees ok */
}
return WSECURESOCKET_ERROR;
}
else
break; /* ok */
}
return WSECURESOCKET_OK;
}
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server, long timeoutMs)
{
int ret;
/* secure socket connected to a server */
SetBlocking(sock, WSOCKET_NONBLOCKING);
ctx->sslClient = SSL_new(ctx->clientSecureCtx);
SSL_set_fd(ctx->sslClient, sock);
AddSsl(e, ctx, ctx->sslClient, sock); /* TODO array */
SSL_set_tlsext_host_name(ctx->sslClient, server->mPtr); /* necessaire sur google.fr par exemple, a garder ? */
/* */
for(;;) // TODO mettre un timeout global !?
{
if((ret = processSSLresponse(e, ctx, ctx->sslClient, SSL_connect(ctx->sslClient))) < 0)
{
if(ret == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, sock, timeoutMs);
if(cr >= 0)
continue; /* donnees ok */
}
if(ret == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, sock, timeoutMs);
if(cr >= 0)
continue; /* donnees ok */
}
return WSECURESOCKET_ERROR;
}
else
break; /* ok */
}
/* */
if(SSL_get_verify_result(ctx->sslClient) != X509_V_OK)
return WSECURESOCKET_ERROR;
X509 * cert;
if( ! (cert = SSL_get_peer_certificate(ctx->sslClient)) )
return WSECURESOCKET_ERROR;
int cr = X509_check_host(cert, server->mPtr, 0, 0, NULL);
X509_free(cert);
if(cr != 1)
return WSECURESOCKET_ERROR;
/* */
return WSECURESOCKET_OK;
}
WAPIDECL long ReadSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs)
{
SSL * ssl;
if(!(ssl = GetSsl(e, ctx, sock))) return WSECURESOCKET_ERROR; /* TODO array */
/* */
int packetLg = ctx->packet, nbRead;
/* */
for(;;)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr < 0)
return WSECURESOCKET_ERROR;
else if(cr == 0)
return WSECURESOCKET_OK; /* => timeout, RAS en lecture */
/* prepare la prochaine lecture */
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
return WSECURESOCKET_MEM_ERROR; // erreur memoire
for(;;)
{
if((nbRead = processSSLresponse(e, ctx, ssl, SSL_read(ssl, data->mPtr + data->mLg, packetLg))) < 0)
{
if(nbRead == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr <= 0)
return WSECURESOCKET_ERROR;
continue;
}
if(nbRead == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr <= 0)
return WSECURESOCKET_ERROR;
continue;
}
return WSECURESOCKET_ERROR;
}
dynSetLen(e, data, data->mLg + nbRead);
if(nbRead < packetLg)
return WSECURESOCKET_OK;
/* si lg maxi lue, sans doute d'autres donnees a lire : continuer (ou faire systematiquement ?) */
break;
}
}
}
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, Socket sock, var * data, long timeoutMs)
{
SSL * ssl;
if(!(ssl = GetSsl(e, ctx, sock))) return WSECURESOCKET_ERROR; /* TODO array */
/* */
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr <= 0)
return WSECURESOCKET_ERROR; /* timeout = error */
/* */
ent64s dejaLu = 0;
int nbWrite;
for(;;)
{
if((nbWrite = processSSLresponse(e, ctx, ssl, SSL_write(ssl, data->mPtr + dejaLu, data->mLg - dejaLu))) < 0)
{
if(nbWrite == WSECURESOCKET_WANTREAD)
{
long cr = WaitOneSocketForRead(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr > 0)
continue;
}
if(nbWrite == WSECURESOCKET_WANTWRITE)
{
long cr = WaitOneSocketForWrite(e, &ctx->ctxSock, ctx->ctxSock.sock, timeoutMs);
if(cr > 0)
continue;
}
return WSECURESOCKET_ERROR;
}
else
{
if(nbWrite >= data->mLg - dejaLu)
break; /* data ok */
/* tout n'a pas ete ecrit : continuer */
dejaLu += nbWrite;
}
}
return WSECURESOCKET_OK;
}
+20 -8
View File
@@ -25,11 +25,11 @@
#include <string.h>
#ifndef WINLIB
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#else
#include <windows.h>
#include <windows.h>
#endif
#include "langage.h"
@@ -38,6 +38,12 @@
typedef int key_t;
#endif
/* codes a passer a la fonction setError */
enum {
EXMOD_BUFFER_INIT = 1,
EXMOD_BUFFER_WRITE = 2
};
typedef struct {
// proprietaire
key_t cle;
@@ -46,8 +52,11 @@ typedef struct {
var * buffer;
#ifndef WINLIB
int handle;
int semId;
#else
HANDLE handle;
char semDesti[25]; // 23 cars + '#' + \0 (different desti sinon ko sous windows)
HANDLE newProcess; // writer: handle process creee en SUSPEND, reader : handle passe en arg et convertit en num
#endif
// destinataire
char desti[24]; // 23 cars + \0
@@ -55,7 +64,10 @@ typedef struct {
var * message;
} modContextShm;
void initShm(env * e, modContextShm * ctx);
void freeShm(env * e, modContextShm * ctx);
void readShm(env * e, modContextShm * ctx);
void writeShm(env * e, modContextShm * ctx);
WAPIDECL void initShm(env * e, modContextShm * ctx);
WAPIDECL void freeShm(env * e, modContextShm * ctx);
WAPIDECL long readShm(env * e, modContextShm * ctx);
WAPIDECL long writeShm(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx);
+131 -52
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,108 +27,187 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
/* ============================================================================================= */
#include "shm.h"
typedef struct {
int error; // dernier code erreur specifique au module
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextShm cs;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_PROCESSNAME_TOOLONG = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Name of process too long (from 1 to 23)"
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#include "mod.c"
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initShm(e, &p_etat->cs);
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
var * prog;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_PROG), &prog);
// maj ctx avec _prog et taille
*((ent64 *)(p_etat->cs.nom)) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 1) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 2) = 0;
if(prog && prog->type == VAR_DYNAMIC && prog->mLg < 24)
strncpy(p_etat->cs.nom, prog->mPtr, prog->mLg);
p_etat->cs.taille = 4000;
//
initShm(e, &p_etat->cs);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//*** code specifique ici
freeShm(e, &p_etat->cs);
//*** FIN du code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "xxx", 3))
else if(modFnIs(e, "get", 3))
{
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
exc = setError(p_etat, EXMOD_xxx);
/* get param in the right order */
var * paramContent = getParam(e, "content", 7);
if(paramContent == NULL)
exc = EX_MODPARAM;
else
{
if(paramContent->type != VAR_DYNAMIC)
var_let(e, paramContent, &e->int_dynamic, FALSE, FALSE);
p_etat->cs.message = paramContent;
exc = setError(p_etat, readShm(e, &p_etat->cs)); // paramContent renvoye a vide si rien a lire
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
/* get param in the right order */
var * paramTextMessage = getParam(e, "textMessage", 11);
var * paramProcessName = getParam(e, "processName", 11);
if(paramTextMessage == NULL || paramProcessName == NULL)
exc = EX_MODPARAM;
else if(paramTextMessage->type != VAR_DYNAMIC || paramProcessName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
*((ent64 *)(p_etat->cs.desti)) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 1) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 2) = 0;
if(paramProcessName->mLg > 0 && paramProcessName->mLg < 24)
{
strncpy(p_etat->cs.desti, paramProcessName->mPtr, paramProcessName->mLg);
p_etat->cs.message = paramTextMessage;
exc = setError(p_etat, writeShm(e, &p_etat->cs));
}
else
exc = setError(p_etat, EXMOD_PROCESSNAME_TOOLONG);
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
/* **************************************************************************************************** */
+341 -25
View File
@@ -23,10 +23,31 @@
#include "shm.h"
#include "buffer.h"
#include "dynamic.h"
#include <errno.h>
#define SHM_MIN_SIZE 1000
#ifndef WINLIB
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#endif
/* PRIVATE */
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
enum {
NBSEM = 1
};
/* ****** PRIVATE ************************ */
static key_t Hash32(const char * cle, int lg)
{
// lg multiple de 4 et > 0
@@ -58,36 +79,55 @@ static key_t Hash32(const char * cle, int lg)
return (key_t)h;
}
/* --------------------------------------------------------------------------------------- */
void initShm(env * e, modContextShm * ctx)
/* ****** PUBLIC ************************ */
WAPIDECL void initShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
ctx->buffer = NULL;
ctx->handle = -1;
ctx->semId = -1;
// creer la sharedmemory du process, pour lecture
if(ctx->taille < SHM_MIN_SIZE)
return; // erreur buffer trop petit
// ne pas controler la taille, sera fait par 'shmget'
// calculer la cle a partir du nom du prog (ctx->nom)
ctx->cle = Hash32(ctx->nom, 24); // chaine de 23 cars + \0
ctx->cle = Hash32(ctx->nom, 24); // chaine de 23 cars max + \0 de fin
// securite : supprimer un eventuel reliquat d'un ancien shm ? Faire un appel externe pas systematique, que le createur, (ou mettre un flag)
//shmctl(ctx->cle, IPC_RMID, NULL);
// creer le buffer
ctx->handle = shmget(ctx->cle, ctx->taille, IPC_CREAT | IPC_EXCL | 0x666); // < 0 si ko
ctx->handle = shmget(ctx->cle, ctx->taille, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(ctx->handle < 0)
return; // erreur creation sharedmemory
// lire le pointeur
ctx->buffer = (var *)shmat(ctx->handle, NULL, 0);
if( ! ctx->buffer)
if(ctx->buffer == (var *)(-1))
{
shmctl(ctx->handle, IPC_RMID, NULL);
ctx->buffer = NULL;
ctx->handle = -1;
return; // erreur recup pointeur
}
// creer le semaphore pour les writers
ctx->semId = semget(ctx->cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(ctx->semId < 0)
{
freeShm(e, ctx); // erreur
return;
}
// init semaphore
unsigned short table[NBSEM];
table[0] = 1;
if(semctl(ctx->semId, 0, SETALL, table) < 0)
{
freeShm(e, ctx); // erreur
return;
}
#else
ctx->buffer = NULL;
ctx->handle = NULL;
strncpy(ctx->semDesti, ctx->desti, 24);
ctx->semDesti[24] = 0;
ctx->semDesti[strlen(ctx->desti)] = '#';
// creer la sharedmemory du process, pour lecture
if(ctx->taille < SHM_MIN_SIZE)
return; // erreur buffer trop petit
// ne pas controler la taille, sera fait par 'CreateFileMapping'
// la cle est directement le nom
// creer le buffer
ctx->handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->taille, ctx->nom); // NULL si ko, attention au \0 de fin de ctx->nom
@@ -97,6 +137,7 @@ void initShm(env * e, modContextShm * ctx)
if( ! ctx->buffer)
{
CloseHandle(ctx->handle);
ctx->buffer = NULL;
ctx->handle = NULL;
return; // erreur recup pointeur
}
@@ -105,31 +146,46 @@ void initShm(env * e, modContextShm * ctx)
ctx->buffer->lgmax = ctx->taille - sizeof(var);
ctx->buffer->read = 0;
ctx->buffer->write = 0;
ctx->buffer->ptr = (pointeur)ctx->buffer + sizeof(var); // le contenu est a la suite de l'entete de la variable
ctx->buffer->ptr = NULL; // NULL signifie que le contenu est a la suite de l'entete de la variable (utilise uniquement ici avec les IPC)
}
void freeShm(env * e, modContextShm * ctx)
WAPIDECL void freeShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
if(ctx->buffer)
shmdt(ctx->buffer);
if(ctx->handle >= 0)
shmctl(ctx->handle, IPC_RMID, NULL);
if(ctx->semId >= 0)
semctl(ctx->semId, IPC_RMID, 0);
ctx->buffer = NULL;
ctx->handle = -1;
ctx->semId = -1;
#else
if(ctx->buffer)
UnmapViewOfFile(ctx->buffer);
if(ctx->handle >= 0)
CloseHandle(ctx->handle); // verif que bien detruit
ctx->buffer = NULL;
ctx->handle = NULL;
#endif
}
void readShm(env * e, modContextShm * ctx)
WAPIDECL long readShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
if( ! ctx->buffer || ctx->handle < 0)
return EXMOD_BUFFER_INIT;
#else
if( ! ctx->buffer || ! ctx->handle)
return EXMOD_BUFFER_INIT;
#endif
buffer_read(e, ctx->buffer, ctx->message);
// e->exception != OK si exception en lecture (que EX_MEM) ! vide si rien a lire (Dynamic)
return e->exception;
}
void writeShm(env * e, modContextShm * ctx)
WAPIDECL long writeShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
// calculer la cle a partir du nom du prog (ctx->nom)
@@ -137,39 +193,299 @@ void writeShm(env * e, modContextShm * ctx)
// acceder au buffer
int handle = shmget(cle, 0, 0);
if(handle < 0)
return; // erreur access
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
var * buffer = (var *)shmat(handle, NULL, 0);
if( ! buffer)
return; // seul le ptr se libere
if(buffer == (var *)(-1))
return EXMOD_BUFFER_WRITE; // seul le ptr se libere
// prendre le verrou (semaphore) pour ecrire, avec attente
int semId = semget(cle, NBSEM, 0);
if(semId < 0)
{
shmdt(buffer);
return EXMOD_BUFFER_WRITE;
}
struct sembuf bufw;
bufw.sem_num = 0;
bufw.sem_op = -1; // prendre
bufw.sem_flg = SEM_UNDO; // | IPC_NOWAIT ?
if(semop(semId, &bufw, 1) < 0)
{
shmdt(buffer);
return EXMOD_BUFFER_WRITE;
}
// EcrireBuffer
buffer_write(e, buffer, ctx->message);
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
// liberer le verrou
bufw.sem_op = 1; // liberer
semop(semId, &bufw, 1);
// ne liberer que le ptr sous unix
shmdt(buffer);
#else
// la cle est directement le destinataire
HANDLE handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, ctx->desti); // attention au \0 de fin
if( ! handle)
return; // erreur access
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
var * buffer = (var *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! buffer)
{
CloseHandle(handle);
return; // erreur recup pointeur
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// prendre le verrou (semaphore) pour ecrire, avec attente
HANDLE hSem = CreateSemaphore(NULL, 1, 1, ctx->semDesti); // NULL si erreur
if( ! hSem)
{
UnmapViewOfFile(buffer);
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
if(WaitForSingleObject(hSem, 0) != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur ; 0 = timeout en secondes
{
ReleaseSemaphore(hSem, 1, NULL);
UnmapViewOfFile(buffer);
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// EcrireBuffer
buffer_write(e, buffer, ctx->message);
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
// liberer le verrou
ReleaseSemaphore(hSem, 1, NULL);
// liberations
UnmapViewOfFile(buffer);
CloseHandle(handle);
#endif
return e->exception;
}
/*
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg); DispatchMessage(&msg);
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, ctx->message->lg + sizeLg, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
*/
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// ne liberer que le ptr sous unix
shmdt(data);
#else
// la cle est directement le destinataire
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->message->lg + sizeLg, ctx->desti); // attention au \0 de fin
if( ! handle)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// dupliquer le HANDLE sur le mapping
HANDLE dup = NULL;
if( ! DuplicateHandle(GetCurrentProcess(), handle, ctx->newProcess, &dup, 0, FALSE, DUPLICATE_SAME_ACCESS))// FALSE : le handle dupliqué n’a pas besoin d’être héritable
e->exception = EXMOD_BUFFER_WRITE;
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, 0, 0); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// ne liberer que le ptr sous unix
shmdt(data);
shmctl(handle, IPC_RMID, NULL);
#else
// lire le pointeur, a partir du handle lu de la ligne de commande
HANDLE handle = ctx->newProcess;
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
#ifndef WINLIB
WAPIDECL int OpenLock(env * e, const char * name)
{
key_t cle = Hash32(name, 24); // chaine de 23 cars max + \0 de fin
int semId = semget(cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666);
if(semId < 0)
{
if(errno != EEXIST)
return -1; // erreur
// deja cree, ok
semId = semget(cle, NBSEM, 0);
if(semId < 0)
{
return -1; // erreur
}
}
else
{
// init semaphore
unsigned short table[NBSEM];
table[0] = 1;
if(semctl(semId, 0, SETALL, table) < 0)
{
semctl(semId, IPC_RMID, 0);
return -1; // erreur
}
}
return semId; // >=0 : ok
}
#else
WAPIDECL HANDLE OpenLock(env * e, const char * name)
{
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
char fullName[40] = {0};
if(strlen(name) > 23)
return NULL; // nom trop long
//
strcpy(fullName, "Global\\");
strcat(fullName, name);
HANDLE hSem = CreateSemaphore(&sa, 1, 1, fullName); // 1 = valeur initiale du semaphore ; 1 = valeur max du semaphore ; nom du semaphore (unique)
if( ! hSem)
return NULL; // erreur (si existe, ne passe pas ici, hSem est renseigne avec le sem existant) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur, dans ce cas hSem n'est pas NULL
else
return hSem;
}
#endif
#ifndef WINLIB
WAPIDECL void CloseLock(env * e, int semId)
{
if(semId >= 0)
semctl(semId, IPC_RMID, 0);
}
#else
WAPIDECL void CloseLock(env * e, HANDLE hSem)
{
CloseHandle(hSem);
}
#endif
#ifndef WINLIB
WAPIDECL int SetLock(env * e, int semId, int milliSec)
{
// prendre le verrou (semaphore) pour ecrire, avec attente
struct sembuf bufw;
struct timespec ts;
ts.tv_sec = milliSec / 1000;
ts.tv_nsec = (milliSec % 1000) * 1000000; // xxx ms
bufw.sem_num = 0;
bufw.sem_op = -1; // prendre
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
if(semop(semId, &bufw, 1) < 0)
{
if(errno != EAGAIN)
return -1; // erreur : semaphore ko
// semaphore pris : attendre et reessayer une fois
nanosleep(&ts, NULL);
if(semop(semId, &bufw, 1) < 0)
{
if(errno != EAGAIN)
return -1; // erreur : semaphore ko
return 0; // sortie en timeout cette fois
}
}
return 1; // ok
}
#else
WAPIDECL int SetLock(env * e, HANDLE hSem, int milliSec)
{
int cr = WaitForSingleObject(hSem, milliSec);
if( cr != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur
{
// semaphore pris : attendre ?
if(cr != WAIT_TIMEOUT)
return -1; // erreur
// sortie en time out, semaphore pris, attendre ?
return 0;
}
return 1;
}
#endif
#ifndef WINLIB
WAPIDECL void UnsetLock(env * e, int semId)
{
// liberer le verrou
struct sembuf bufw;
bufw.sem_num = 0;
bufw.sem_op = 1; // liberer
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
semop(semId, &bufw, 1);
}
#else
WAPIDECL void UnsetLock(env * e, HANDLE hSem)
{
// liberer le semaphore
ReleaseSemaphore(hSem, 1, NULL);
}
#endif
+95
View File
@@ -0,0 +1,95 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#ifndef WINLIB
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <poll.h>
#include <unistd.h>
typedef int Socket;
typedef struct pollfd * wPoll;
#define INVALID_SOCKET -1
#else
#include "winsock2.h" // link avec ws2_32.lib
#include <windows.h>
typedef SOCKET Socket;
typedef Socket * wPoll;
#endif
/* codes a passer a la fonction setError */
enum {
WSOCKET_END_CONNECT = -3,
WSOCKET_MEM_ERROR = -2,
WSOCKET_ERROR = -1,
WSOCKET_OK = 0,
WSOCKET_LISTEN_MAX = 10,
/* */
WSOCKET_BLOCKING = 0,
WSOCKET_NONBLOCKING = 1
};
typedef struct {
Dynamic listSocket; // contient le tableau de pollfd/Socket encapsule dans un dynamic
int nbSocket; // nombre d'elements dans le tableau de pollfd
int posAddSocket; // endroit ou l'ajout a ete fait dans listSocket
wPoll poll; // pointeur vers le tableau de pollfd/Socket
Socket servSock;
Socket sock; // socket en cours (tmp)
int packet; // taille des paquets lus un par un
int err; // derniere erreur socket (errno ou WSAGetLastError())
#ifdef WINLIB
fd_set fds;
struct timeval tv;
#endif
} modContextSocket;
WAPIDECL void initSock(env * e, modContextSocket * ctx);
WAPIDECL void freeSock(env * e, modContextSocket * ctx);
WAPIDECL void SetBlocking(Socket sock, int blocking);
WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx);
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port);
WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx);
WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * server);
WAPIDECL long AddSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL void DelSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL long WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL long WaitSocketForWrite(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL long WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs);
WAPIDECL long WaitOneSocketForWrite(env * e, modContextSocket * ctx, Socket sock, int timeoutMs);
WAPIDECL void FreeSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL int GetSocketError();
WAPIDECL int SocketWouldBlock();
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data, long timeoutMs);
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data);
+361 -421
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -25,487 +25,427 @@
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include <signal.h>
#include <errno.h>
#ifdef UNIX
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#ifdef WINLIB
#include "winsock2.h"
#include "windows.h"
#else
#include "windows.h"
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <sys/utsname.h>
#endif
#include "langage.h"
#include "dynamic.h"
/* ============================================================================================= */
#include "sock.h"
typedef struct {
int error; /* dernier code erreur specifique au module */
//***
long mSocket; /* socket en cours */
int mServeur; /* 0 socket serveur mere en ecoute, 1 socket serveur fille connectee a un client, 2 socket client */
#ifdef UNIX
sigset_t mOldBlockSig,mBlockSig; /* gestion des signaux sur socket serveur en ecoute */
#endif
// TODO : gerer plusieurs sockets (serveur ? client ?)
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextSocket ctxSock;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
enum {
EXMOD_SOCK_SERVER_PORT_NUM = 1,
EXMOD_SOCK_SERVER_PORT_INVALID = 2,
EXMOD_SOCK_NEW = 3,
EXMOD_SOCK_SETSERVER = 4,
EXMOD_SOCK_CONNECT = 5,
EXMOD_SOCK_WAIT = 6,
EXMOD_SOCK_ACCEPT = 7,
EXMOD_SOCK_READ = 8,
EXMOD_SOCK_WRITE = 9,
EXMOD_SOCK_NOTNUM = 10,
EXMOD_SOCK_GETHOST = 11,
EXMOD_SOCK_GETNAME = 12,
EXMOD_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"
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// fonction createServer, arret
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
p_etat->mSocket = 0;
p_etat->mServeur = 0;
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initSock(e, &p_etat->ctxSock);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
//***
if(p_etat->mSocket > 0)
close(p_etat->mSocket);
//***
//*** code specifique ici
freeSock(e, &p_etat->ctxSock);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(p_etat == NULL)
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
exc = EX_MODETAT;
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "server", 6) == 0)
else if(modFnIs(e, "server", 6))
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
{
exc = EX_MODETAT;
return exc;
}
// param<1> = numero de port ; TODO : mettre une VAR_NUMBER ??
long port = dynToNum(e, param, 0, 5);
if(param->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
}
if(port < 1024 || port > 65535)
{
exc = setError(p_etat, 1);
return exc;
}
//
struct sockaddr_in addr;
struct linger l_s; /* Structure pour setsockopt */
int sockopt, buf = 64000; /* taille buffer send/rec = 64 ko environ */
int arg = 1; /* pour ioctl */
// cree une socket serveur prete a ecouter
/* mise en place de la socket serveur d'ecoute */
if((p_etat->mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */
#endif
/* */
#ifdef UNIX
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
#endif
/* */
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
// linger n'impacte QUE le close de la socket
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if(bind(p_etat->mSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* get param in the right order */
var * paramPortNumber = getParam(e, "portNumber", 10);
if(paramPortNumber == NULL)
exc = EX_MODPARAM;
else if(paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
if(listen(p_etat->mSocket, 10) < 0)
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
{
/* cree un point d'entree serveur */
number port;
if( ! var_conv_num(e, paramPortNumber, &port))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM);
else if(port < 1024 * NUM_FACTEUR || port > 65535 * NUM_FACTEUR)
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_INVALID); /* en dessous de 1024, necessite des autorisations speciales, non gere ici */
else
{
/* socket non bloquante (autre possibilite) */
//fcntl(sock, F_GETFL, &sockopt);
//fcntl(sock, F_SETFL, sockopt|O_NONBLOCK);
/* OK */
p_etat->mServeur = 0;
#ifdef UNIX
sigemptyset(&p_etat->mOldBlockSig);
sigfillset(&p_etat->mBlockSig);
#endif
if(NewSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
if(SocketSetServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR)) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SOCK_SETSERVER);
}
else
exc = setError(p_etat, EXMOD_SOCK_NEW);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "connect", 7) == 0)
else if(modFnIs(e, "connect", 7))
{
char ** tParam;
/* connexion a un serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(dynDcount(e, param, cFM, DYN_NONE, DYN_NONE) < 2)
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramPortNumber = getParam(e, "portNumber", 10);
var * paramSocket = getParam(e, "socket", 6);
if(paramHost == NULL || paramPortNumber == NULL || paramSocket == NULL)
exc = EX_MODPARAM;
else if(paramHost->type != VAR_DYNAMIC || (paramPortNumber->type != VAR_NUMBER && paramPortNumber->type != VAR_DYNAMIC))
exc = EX_MODPARAM;
else
{
/* connexion a un serveur */
number port;
if( ! var_conv_num(e, paramPortNumber, &port))
exc = setError(p_etat, EXMOD_SOCK_SERVER_PORT_NUM);
else
{
if(NewSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
if(SocketConnectToServer(e, &p_etat->ctxSock, p_etat->ctxSock.sock, (int)(port / NUM_FACTEUR), paramHost) == WSOCKET_OK)
{
if(paramSocket->type != VAR_NUMBER)
var_let(e, paramSocket, &e->int_number, FALSE, FALSE);
paramSocket->num = p_etat->ctxSock.sock; /* (sock * NUM_FACTEUR) ? */
}
else
exc = setError(p_etat, EXMOD_SOCK_CONNECT);
}
else
exc = setError(p_etat, EXMOD_SOCK_NEW);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stopServer", 10))
{
/* arret serveur */
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.servSock);
p_etat->ctxSock.servSock = INVALID_SOCKET;
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stop", 4))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
if(paramSocket == NULL)
exc = EX_MODPARAM;
else if(paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* arret connexion */
number socket;
if( var_conv_num(e, paramSocket, &socket) )
FreeSocket(e, &p_etat->ctxSock, socket);
else
exc = setError(p_etat, EXMOD_SOCK_NOTNUM);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "wait", 4))
{
/* get param in the right order */
var * paramTimeout = getParam(e, "timeout", 7);
var * paramClientSock = getParam(e, "clientSock", 10);
if(paramTimeout == NULL || paramClientSock == NULL)
exc = EX_MODPARAM;
else if(paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if( ! var_conv_num(e, paramTimeout, &timeout) )
exc = EX_MODPARAM;
else
{
if(paramClientSock->type != VAR_NUMBER)
var_let(e, paramClientSock, &e->int_number, FALSE, FALSE);
// attend une activite sur la socket serveur et si oui cree une nouvelle socket, timeout en secondes
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, p_etat->ctxSock.servSock, timeout * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
paramClientSock->num = NUM_MOINSUN; /* => timeout, RAS */
else
{
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
paramClientSock->num = p_etat->ctxSock.sock;
}
else
exc = setError(p_etat, EXMOD_SOCK_ACCEPT);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramSocket == NULL || paramData == NULL || paramTimeout == NULL)
exc = EX_MODPARAM; /* erreur */
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC || (paramTimeout->type != VAR_NUMBER && paramTimeout->type != VAR_DYNAMIC))
exc = EX_MODPARAM; /* erreur */
else
{
// param<1> = host (nom ou ip)
// param<2> = port
// decouper en 2 chaines Comm
tParam = dynToTabPtr(e, param, cFM);
if(tParam == NULL)
exc = EX_MODPARAM; /* erreur */
number socket, timeout;
if( var_conv_num(e, paramSocket, &socket) && var_conv_num(e, paramTimeout, &timeout) )
{
if(paramData->type != VAR_DYNAMIC)
{
var_let(e, paramData, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramData, 0);
}
/* lecture sur la connexion : lecture par paquets de longueur fixe et s'arreter des que plus rien a lire
lecture par paquets de <pas> octets */
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, socket, timeout * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
dynSetLen(e, paramData, 0); /* => timeout, RAS */
else
{
/* socket a recu des donnees */
if(ReadSocket(e, &p_etat->ctxSock, socket, paramData, timeout * 1000 / NUM_FACTEUR) != WSOCKET_OK)
/* traiter le cas WSOCKET_END_CONNECT : erreur ? (fin cnx) */
exc = setError(p_etat, EXMOD_SOCK_READ);
}
}
else
exc = EX_MODPARAM;
}
if(exc != OK)
return exc;
long port = atoi(tParam[1]);
if(param->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
}
if(port < 1 || port > 65535)
{
exc = setError(p_etat, 1);
return exc;
}
//
struct hostent * serv;
struct sockaddr_in addr;
struct linger l_s; /* Structure pour setsockopt */
int sockopt, buf = 64000; /* taille buffer send/rec = 64 ko environ */
int arg = 1; /* pour ioctl */
// cree une socket serveur prete a ecouter
/* mise en place de la socket serveur d'ecoute */
if((p_etat->mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */
#endif
/* */
#ifdef UNIX
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
#endif
/* */
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
// linger n'impacte QUE le close de la socket
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
/* pour l'adresse, soit host soit ip */
if((serv = gethostbyname(tParam[0])) == NULL)
; /* erreur */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(serv->h_addr);
if (connect(p_etat->mSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
; /* erreur : lire errno : EISCONN (deja:ok), EINPROGRESS EALREADY (en cours:ressayer), sinon erreur */
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* get param in the right order */
var * paramSocket = getParam(e, "socket", 6);
var * paramData = getParam(e, "data", 4);
if(paramSocket == NULL || paramData == NULL)
exc = EX_MODPARAM; /* erreur */
else if((paramSocket->type != VAR_NUMBER && paramSocket->type != VAR_DYNAMIC) || paramData->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
else
{
p_etat->mServeur = 2; /* client */
#ifdef UNIX
sigemptyset(&p_etat->mOldBlockSig);
sigfillset(&p_etat->mBlockSig);
number socket;
if( var_conv_num(e, paramSocket, &socket) )
{
/* ecriture sur la connexion */
if(WriteSocket(e, &p_etat->ctxSock, socket, paramData) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SOCK_WRITE);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "getHostname", 11))
{
/* get param in the right order */
var * paramName = getParam(e, "name", 4);
var * paramIp = getParam(e, "ip", 2);
if(paramName == NULL || paramIp == NULL)
exc = EX_MODPARAM;
else
{
if(paramName->type != VAR_DYNAMIC)
var_let(e, paramName, &e->int_dynamic, FALSE, FALSE);
if(paramIp->type != VAR_DYNAMIC)
var_let(e, paramIp, &e->int_dynamic, FALSE, FALSE);
#ifdef WINLIB
long size = paramName->mLgmax;
if (!GetComputerNameA(paramName->mPtr, &size))
exc = setError(p_etat, EXMOD_SOCK_GETNAME);
else
{
dynSetLen(e, paramName, strlen(paramName->mPtr));
if (gethostname(paramIp->mPtr, paramIp->mLgmax) == SOCKET_ERROR)
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
else
{
struct hostent * host_entry;
host_entry = gethostbyname(paramIp->mPtr);
dynSetLen(e, paramIp, 0); // paramIp var tmp ici
if (host_entry == NULL)
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
else if(host_entry->h_addr_list == NULL)
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
else
{
dynLet(e, paramIp, inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]), DYN_LGNONE);
}
}
}
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
{
if(dynCtrl(e, paramName, (lg = strlen(name.nodename)), DYN_FALSE) == DYN_OK)
{
dynLet(e, paramName, name.nodename, lg);
// lecture ip
struct hostent * host = gethostbyname(paramName->mPtr);
if(host)
dynLet(e, paramIp, inet_ntoa(*(struct in_addr *)host->h_addr_list[0]), DYN_LGNONE);
else
exc = setError(p_etat, EXMOD_SOCK_GETHOST);
}
else
exc = EX_MEM;
}
else
exc = setError(p_etat, EXMOD_SOCK_GETNAME);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "arret", 5) == 0)
{
/* arret connexion cliente ou serveur */
if(p_etat != NULL)
{
shutdown(p_etat->mSocket, 2);
close(p_etat->mSocket);
p_etat->mSocket = 0;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "attente", 7) == 0)
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
fd_set masque;
struct timeval delai;
long cr;
// attend une activite sur la socket, timeOut en 1/10 de sec.
delai.tv_sec = param->num / NUM_FACTEUR; // x sec
delai.tv_usec = (param->num % NUM_FACTEUR) * 10; // y µsec
FD_ZERO(&masque);
FD_SET(p_etat->mSocket, &masque);
//
if(p_etat->mServeur == 0)
{
// pour que le select() fonctionne a chaque fois (a chaque time-out), il faut remettre à jour
// les variables "delai" et "masque fd" ; il faut aussi imperativement
// bloquer les signaux !! la socket peut etre bloquante (mais il vaut mieux la mettre non bloquante)
#ifdef UNIX
sigprocmask(SIG_SETMASK, &p_etat->mBlockSig, &p_etat->mOldBlockSig);
#endif
cr = select(p_etat->mSocket + 1, &masque, NULL, NULL, &delai);
#ifdef UNIX
sigprocmask(SIG_SETMASK, &p_etat->mOldBlockSig, NULL);
#endif
}
else
{
while((cr = select(p_etat->mSocket + 1, &masque, NULL, NULL, &delai)) < 0 && errno == EINTR) errno = 0;
if(cr > 0)
cr = FD_ISSET(p_etat->mSocket, &masque);
}
if(cr > 0)
param->num = NUM_UN; /* ok pour lire */
else
param->num = NUM_ZERO; /* pas de donnees */
// si cr > 0 : ok pour continuer et lire la socket
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "get", 3) == 0)
{
long nblu = 0, arg = 1, flagInProgress = 0, pas = 16000, would_block;
/* lecture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
// lire par paquets de longueur fixe et s'arrêter dès que plus rien à lire
// lecture par paquets de <pas> octets
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) necessaire quand la longueur n'est pas connue (sinon lire sur la longueur et laisser(?) la socket bloquante) */
#endif
dynSetLen(e, param, 0);
do
{
if(!dynCtrl(e, param, param->mLg + pas, 1)) /* avec recopie */
{
exc = setError(p_etat, 1);
break;
}
would_block = 0;
while((nblu = read(p_etat->mSocket, param->mPtr + param->mLg, pas)) < 0 && errno == EWOULDBLOCK /* WouldBlock = 11 */
&& (param->mLg == 0 || flagInProgress) && (++would_block) < 100)
#ifdef UNIX
usleep(10000); /* attente de 10 ms entre chaque appel, maxi 100 fois (a garder ?) */
#else
Sleep(10);
#endif
if(errno == EINPROGRESS) /* 115 */
flagInProgress = 1; /* indique un envoi en plusieurs parties : ne plus sortir quand getLen # 0 car lecture pas finie ! */
if(nblu > 0)
dynSetLen(e, param, param->mLg + nblu);
/* */
} while (nblu > 0);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "set", 3) == 0)
{
long nb , pos = 0, lg, would_block;
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
lg = param->mLg;
while(lg > 0)
{
would_block = 0;
while((nb = write(p_etat->mSocket, param->mPtr + pos, lg)) < 0 && errno == EWOULDBLOCK
&& (++would_block) < 100)
#ifdef UNIX
usleep(10000); /* attente 10 ms entre chaque appel, maxi 100 fois (a garder ?) */
#else
Sleep(10);
#endif
if(nb <= 0)
{
exc = setError(p_etat, 2);
break;
}
lg -= nb;
if(lg > 0)
pos += nb; /* ecriture en plusieurs fois */
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "accept", 6) == 0)
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
struct sockaddr_in addr_cnx;
unsigned int size_addr_cnx = sizeof(addr_cnx);
int sock;
if((sock = accept(p_etat->mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
param->num = sock * NUM_FACTEUR; /* nouvelle requete entrante : renvoie num socket */
else
param->num = NUM_ZERO; /* pas de nouvelle connexion entrante finalement */
}
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+617
View File
@@ -0,0 +1,617 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "sock.h"
#include "dynamic.h"
#include <errno.h>
#include <fcntl.h>
#ifdef WINLIB
#include <ws2tcpip.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/* ****** PRIVATE ************************ */
/* ****** PUBLIC ************************ */
WAPIDECL void initSock(env * e, modContextSocket * ctx)
{
dynInit(e, &ctx->listSocket, DYN_LGMIN);
dynSetLen(e, &ctx->listSocket, 0); // raz liste sockets
ctx->servSock = INVALID_SOCKET;
ctx->sock = INVALID_SOCKET;
ctx->packet = 16000;
ctx->nbSocket = 0;
//
#ifdef WINLIB
WSADATA wsa;
WSAStartup(MAKEWORD(2,2), &wsa);
#endif
}
WAPIDECL void freeSock(env * e, modContextSocket * ctx)
{
/* fermer les sockets ouvertes */
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
{
#ifndef WINLIB
shutdown(ctx->poll[cpt].fd, SHUT_RDWR);
close(ctx->poll[cpt].fd);
#else
shutdown(ctx->poll[cpt], SD_BOTH);
closesocket(ctx->poll[cpt]);
#endif
}
dynFree(e, &ctx->listSocket);
#ifdef WINLIB
WSACleanup();
#endif
}
WAPIDECL void SetBlocking(Socket sock, int blocking)
{
#ifndef WINLIB
int sockopt = blocking; // 1 = non-bloquant, 0 = bloquant
ioctl(sock, FIONBIO, &sockopt);
#else
u_long block_mode = blocking; // 1 = non-bloquant, 0 = bloquant
ioctlsocket(sock, FIONBIO, &block_mode);
#endif
}
WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx)
{
#ifdef WINLIB
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
int iOptVal = 0;
int iOptLen = sizeof(int);
u_long block_mode = 1; // 1 = non-bloquant, 0 = bloquant
#else
int sockopt = 1; // 1 = non-bloquant, 0 = bloquant
#endif
struct linger l_s; /* Structure pour setsockopt */
Socket sock;
/* */
#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
{
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
SetBlocking(sock, WSOCKET_NONBLOCKING);
/* */
/* voir ici https://learn.microsoft.com/fr-fr/windows/win32/api/winsock/nf-winsock-setsockopt pour les parametres a passer selon l'option */
#ifndef WINLIB
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
#else
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen)) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return WSOCKET_ERROR;
}
/* linger n'impacte QUE le close de la socket */
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return WSOCKET_ERROR;
}
/* autres options ?
int buf = 64000; // de 4 ko a 256 Ko, mais impact tres limite => prevoir plutot un heartbeat applicatif
if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf))) ; // erreur
if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf))) ;
// keep alive ?
#ifndef WINLIB
// Activer SO_KEEPALIVE
int yes = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes))) ; // erreur
// Apres 30s d'inactivite, commencer les sondes
int idle = 30;
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle))) ;
// Intervalle de 10s entre sondes
int interval = 10;
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval))) ;
// 3 tentatives avant abandon
int maxpkt = 3;
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt))) ;
#else
// sous windows, seuls les parametres temporels se font differemment :
BOOL optval = TRUE;
if(setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval))) ;
struct tcp_keepalive keepalive;
keepalive.onoff = 1;
keepalive.keepalivetime = 30000; // 30 secondes avant 1ere sonde
keepalive.keepaliveinterval = 10000; // 10 secondes entre sondes
if(WSAIoctl(sock, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), NULL, 0, &bytesReturned, NULL, NULL) == SOCKET_ERROR) ;
#endif
*/
ctx->sock = sock;
return WSOCKET_OK;
}
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port)
{
struct sockaddr_in addr;
//
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
#ifndef WINLIB
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
#else
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return WSOCKET_ERROR;
}
#ifndef WINLIB
if(listen(sock, WSOCKET_LISTEN_MAX) < 0)
#else
if(listen(sock, WSOCKET_LISTEN_MAX) == SOCKET_ERROR)
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return WSOCKET_ERROR;
}
if(AddSocket(e, ctx, sock) == WSOCKET_OK)
{
ctx->servSock = sock;
return WSOCKET_OK;
}
else
return WSOCKET_ERROR;
}
WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx)
{
struct sockaddr_in addr_cnx;
ctx->sock = 0;
#ifndef WINLIB
unsigned int size_addr_cnx = sizeof(addr_cnx);
if((ctx->sock = accept(ctx->servSock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
#else
int size_addr_cnx = sizeof(addr_cnx);
if((ctx->sock = accept(ctx->servSock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) != INVALID_SOCKET)
#endif
{
if(AddSocket(e, ctx, ctx->sock) == WSOCKET_OK)
return WSOCKET_OK;
else
{
#ifdef WINLIB
closesocket(ctx->sock);
#else
close(ctx->sock);
#endif
return WSOCKET_ERROR;
}
}
else
{
ctx->err = GetSocketError();
return WSOCKET_ERROR;
}
}
WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * 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
{
// 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);
}
/* 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));
#ifdef WINLIB
if (ret == SOCKET_ERROR)
{
if(WSAGetLastError() != WSAEWOULDBLOCK)
{
ctx->err = GetSocketError();
closesocket(sock);
return WSOCKET_ERROR;
}
}
#else
if (ret < 0 && errno != EINPROGRESS)
{
ctx->err = GetSocketError();
close(sock);
return WSOCKET_ERROR;
}
#endif
if(AddSocket(e, ctx, sock) != WSOCKET_OK)
{
#ifdef WINLIB
closesocket(sock);
#else
close(sock);
#endif
return WSOCKET_ERROR;
}
#ifdef WINLIB
FD_ZERO(&ctx->fds);
FD_SET(sock, &ctx->fds);
ctx->tv.tv_sec = 1; // revoir parametre
ctx->tv.tv_usec = 0;
ret = select(0, NULL, &ctx->fds, NULL, &ctx->tv);
#else
ctx->poll[ctx->posAddSocket].events = POLLOUT;
ret = poll(&ctx->poll[ctx->posAddSocket], 1, 1000); // revoir parametres
ctx->poll[ctx->posAddSocket].events = POLLIN;
#endif
if (ret <= 0)
{
ctx->err = GetSocketError();
// timeout (0) ou erreur (<0)
#ifdef WINLIB
closesocket(sock);
#else
close(sock);
#endif
DelSocket(e, ctx, sock);
return WSOCKET_ERROR;
}
else
return WSOCKET_OK;
}
WAPIDECL long AddSocket(env * e, modContextSocket * ctx, Socket sock)
{
#ifndef WINLIB
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
{
ctx->posAddSocket = cpt;
return WSOCKET_OK; // deja present : RAF
}
// ajouter
if(dynCtrl(e, &ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return WSOCKET_MEM_ERROR; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket.ptr;
ctx->posAddSocket = ctx->nbSocket++; // post incrementation car tableau base 0
ctx->poll[ctx->posAddSocket].fd = sock;
ctx->poll[ctx->posAddSocket].events = POLLIN;
return WSOCKET_OK;
#else
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
{
ctx->posAddSocket = cpt;
return WSOCKET_OK; // deja present : RAF
}
// ajouter
if(dynCtrl(e, &ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return WSOCKET_MEM_ERROR; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket.ptr;
ctx->posAddSocket = ctx->nbSocket++; // post incrementation car tableau base 0
ctx->poll[ctx->posAddSocket] = sock;
return WSOCKET_OK;
#endif
}
WAPIDECL void DelSocket(env * e, modContextSocket * ctx, Socket sock)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
if(cpt < --ctx->nbSocket) // autre solution : mettre le fd en negatif : sera ignore par poll
ctx->poll[cpt] = ctx->poll[ctx->nbSocket]; // remplacer par le dernier (bouche le trou tout de suite)
#else
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
if(cpt < --ctx->nbSocket) // autre solution : mettre le fd en negatif : sera ignore par poll
ctx->poll[cpt] = ctx->poll[ctx->nbSocket]; // remplacer par le dernier (bouche le trou tout de suite)
#endif
}
WAPIDECL long WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
{
ctx->poll[cpt].events = POLLIN;
ctx->poll[cpt].revents = 0;
}
return poll(ctx->poll, ctx->nbSocket, timeoutMs);
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
#else
FD_ZERO(&ctx->fds);
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, &ctx->fds, NULL, NULL, &ctx->tv);
#endif
}
WAPIDECL long WaitSocketForWrite(env * e, modContextSocket * ctx, int timeoutMs)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
{
ctx->poll[cpt].events = POLLOUT;
ctx->poll[cpt].revents = 0;
}
return poll(ctx->poll, ctx->nbSocket, timeoutMs);
// socket pret a l'ecriture si (ctx->poll[cpt].revents & POLLOUT) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
#else
FD_ZERO(&ctx->fds);
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, NULL, &ctx->fds, NULL, &ctx->tv);
#endif
}
WAPIDECL long WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
{
ctx->poll[cpt].events = POLLIN;
ctx->poll[cpt].revents = 0;
return poll(&ctx->poll[cpt], 1, timeoutMs);
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
}
#else
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
{
FD_ZERO(&ctx->fds);
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, &ctx->fds, NULL, NULL, &ctx->tv);
}
#endif
return WSOCKET_ERROR;
}
WAPIDECL long WaitOneSocketForWrite(env * e, modContextSocket * ctx, Socket sock, int timeoutMs)
{
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
{
ctx->poll[cpt].events = POLLOUT;
ctx->poll[cpt].revents = 0;
return poll(&ctx->poll[cpt], 1, timeoutMs);
// socket pret a l'ecriture si (ctx->poll[cpt].revents & POLLOUT) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
}
#else
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
{
FD_ZERO(&ctx->fds);
FD_SET(ctx->poll[cpt], &ctx->fds);
ctx->tv.tv_sec = timeoutMs / 1000;
ctx->tv.tv_usec = (timeoutMs % 1000) * 1000;
return select(0, NULL, &ctx->fds, NULL, &ctx->tv);
}
#endif
return WSOCKET_ERROR;
}
WAPIDECL void FreeSocket(env * e, modContextSocket * ctx, Socket sock)
{
#ifndef WINLIB
shutdown(sock, SHUT_RDWR); // inutile a cause de SO_LINGER = 1 !?
close(sock);
#else
shutdown(sock, SD_BOTH); // inutile a cause de SO_LINGER = 1 !?
closesocket(sock);
#endif
DelSocket(e, ctx, sock);
}
WAPIDECL int GetSocketError()
{
#ifdef WINLIB
return WSAGetLastError();
#else
return errno;
#endif
}
WAPIDECL int SocketWouldBlock()
{
int err = GetSocketError();
#ifdef WINLIB
return (err == WSAEWOULDBLOCK || err == WSAEINTR);
#else
return (err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
#endif
}
// https://broux.developpez.com/articles/c/sockets
// https://learn.microsoft.com/fr-fr/windows/win32/winsock/using-winsock
// lecture / ecriture : utiliser send/recv => read/write fait idem avec attribute = 0
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data, long timeoutMs)
{
int packetLg = ctx->packet;
int nbTot = 0;
// code ici avec une socket non bloquante (sinon a revoir) ; ajouter dans la boucle le poll sur la socket quand besoin de reessayer
for(;;)
{
/* TODO : mettre une limite en nb octets lus ? */
int cr = WaitOneSocketForRead(e, ctx, sock, timeoutMs);
if(cr < 0)
{
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
if(cr == 0)
return WSOCKET_OK; /* timeout : renvoi des donnees eventuellement deja lues */
/* */
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
{
return WSOCKET_MEM_ERROR; // erreur memoire
}
#ifdef WINLIB
int nbRead = recv(sock, data->mPtr + data->mLg, packetLg, 0);
#else
int nbRead = recv(sock, data->mPtr + data->mLg, packetLg, 0);
#endif
if(nbRead < 0)
{
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
if(nbRead == 0 && nbTot == 0)
return WSOCKET_END_CONNECT; /* fin de lecture car fin de la comm - A REVOIR */
/* nbRead positif ici */
dynSetLen(e, data, data->mLg + nbRead);
nbTot += nbRead;
if(nbRead < packetLg)
return WSOCKET_OK;
}
}
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data)
{
long len = data->mLg, nbTot = 0, timeoutMs = 1000;
if(len == 0)
return WSOCKET_OK;
/* */
for(;;)
{
int cr = WaitOneSocketForWrite(e, ctx, sock, timeoutMs);
if(cr < 0)
{
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
/* */
#ifdef WINLIB
int nbWrite = send(sock, data->mPtr + nbTot, (int)len, 0);
#else
int nbWrite = send(sock, data->mPtr + nbTot, len, MSG_NOSIGNAL); /* inutile sous Windows et n'arrive QUE en ecriture ! */
#endif
if(nbWrite == 0 && nbTot == 0)
return WSOCKET_END_CONNECT; /* fin d'ecriture car fin de la comm - A REVOIR */
if(nbWrite < 0)
{
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
len -= nbWrite;
nbTot += nbWrite;
if(len <= 0)
return WSOCKET_OK;
}
}
+85
View File
@@ -0,0 +1,85 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
#include "sqlite3.h"
typedef struct {
sqlite3 * sl3Handle;
sqlite3_stmt * sl3Request, * sl3Begin, * sl3Commit, * sl3Rollback, * sl3Cursor;
Dynamic confTable, stmt;
Dynamic request, pkfilter, colPk, colPkType, colAll, colAllType, error;
long nbStmt;
} modCtxSl3;
enum {
SL3ERR_PREPARE = 1,
SL3ERR_BIND = 2,
SL3ERR_NOPK = 3,
SL3ERR_NOTABLEINFO = 4,
SL3ERR_PREPARERW = 5,
SL3ERR_NORECORD = 6,
SL3ERR_COLTYPE = 7,
SL3ERR_READLOCK = 8,
SL3ERR_STEP = 9,
SL3ERR_WRITELOCK = 10,
SL3ERR_CREATE = 11,
SL3ERR_OPEN = 12,
SL3ERR_MEM = 13,
SL3ERR_TABLENOTPREP = 14,
SL3ERR_FETCH = -1
};
WAPIDECL void initSl3(env * e, modCtxSl3 * ctx);
WAPIDECL void freeSl3(env * e, modCtxSl3 * ctx);
WAPIDECL char * getErrorSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long openSl3(env * e, modCtxSl3 * ctx, const char * base);
WAPIDECL long createSl3(env * e, modCtxSl3 * ctx, const char * base);
WAPIDECL void closeSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long beginSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long commitSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long rollbackSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long prepare_rwSl3(env * e, modCtxSl3 * ctx, char * table);
WAPIDECL void remove_rwSl3(env * e, modCtxSl3 * ctx, char * table);
WAPIDECL long getDescSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * desc);
WAPIDECL long readSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * key, Dynamic * record);
WAPIDECL long writeSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * record);
WAPIDECL long cursorSl3(env * e, modCtxSl3 * ctx, Dynamic * request, Dynamic * param);
WAPIDECL long fetchSl3(env * e, modCtxSl3 * ctx, Dynamic * record, long count);
WAPIDECL long createTableSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * colName, Dynamic * colType, long nbPk);
WAPIDECL long removeTableSl3(env * e, modCtxSl3 * ctx, char * table);
/*
1 base = 1 fichier sur disque (rm pour supprimer la base...), open ouvre ou cree la base (il suffit de verifier si le fichier existe...). Encodage = UTF-8
pas d'asynchrone (creer des threads/process) ; PRAGMA table_info(<table>) donne les infos sur une table (colonnes, types, PK etc.) ; pas de notion de schema (tout est dans la meme "base")
syntaxe pour binding dans requetes : ?1 ?2 ou :param1 $param2 @param3
docs : https://sqlite.org/capi3ref.html
sqlite3.c: The SQLite amalgamation source file
sqlite3.h: The header file that accompanies sqlite3.c and defines the C-language interfaces to SQLite.
shell.c: The command-line interface program itself.
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -lm -o sqlite3
gcc -fPIC -shared sqlite3.c -o libsqlite3.so -lpthread -ldl -lm
*/
+268826
View File
File diff suppressed because it is too large. Load diff
+14335
View File
File diff suppressed because it is too large. Load diff
+507
View File
@@ -0,0 +1,507 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sqlite.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
#define SQLITE_TYPE_TEXT "TEXT"
#define SQLITE_TYPE_INTEGER "INTEGER"
WAPIDECL void initSl3(env * e, modCtxSl3 * ctx)
{
dynInit(e, &ctx->stmt, DYN_LGMIN);
dynInit(e, &ctx->confTable, DYN_LGMIN);
dynInit(e, &ctx->request, DYN_LGMIN);
dynInit(e, &ctx->pkfilter, DYN_LGMIN);
dynInit(e, &ctx->colPk, DYN_LGMIN);
dynInit(e, &ctx->colPkType, DYN_LGMIN);
dynInit(e, &ctx->colAll, DYN_LGMIN);
dynInit(e, &ctx->colAllType, DYN_LGMIN);
dynInit(e, &ctx->error, DYN_LGMIN);
ctx->nbStmt = 0;
}
WAPIDECL void freeSl3(env * e, modCtxSl3 * ctx)
{
dynFree(e, &ctx->stmt);
dynFree(e, &ctx->confTable);
dynFree(e, &ctx->request);
dynFree(e, &ctx->pkfilter);
dynFree(e, &ctx->colPk);
dynFree(e, &ctx->colPkType);
dynFree(e, &ctx->colAll);
dynFree(e, &ctx->colAllType);
dynFree(e, &ctx->error);
}
WAPIDECL char * getErrorSl3(env * e, modCtxSl3 * ctx)
{
dynLet(e, &ctx->error, (char *)sqlite3_errmsg(ctx->sl3Handle), DYN_LGNONE);
return ctx->error.mPtr;
}
WAPIDECL long openSl3(env * e, modCtxSl3 * ctx, const char * base)
{
if(sqlite3_open_v2(base, &ctx->sl3Handle, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK)
return SL3ERR_OPEN;
else
{
dynSetLen(e, &ctx->stmt, 0);
ctx->nbStmt = 0;
dynSetLen(e, &ctx->confTable, 0);
// preparation des requetes de transaction
if(sqlite3_prepare_v2(ctx->sl3Handle, "BEGIN TRANSACTION", -1, &ctx->sl3Begin, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
if(sqlite3_prepare_v2(ctx->sl3Handle, "COMMIT TRANSACTION", -1, &ctx->sl3Commit, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
if(sqlite3_prepare_v2(ctx->sl3Handle, "ROLLBACK TRANSACTION", -1, &ctx->sl3Rollback, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
return OK; // connexion a une base ; pour la creer si elle n'existe pas : " | SQLITE_OPEN_CREATE "
}
}
WAPIDECL long createSl3(env * e, modCtxSl3 * ctx, const char * base)
{
if(sqlite3_open_v2(base, &ctx->sl3Handle, SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
return SL3ERR_CREATE;
sqlite3_close(ctx->sl3Handle);
return openSl3(e, ctx, base);
}
WAPIDECL void closeSl3(env * e, modCtxSl3 * ctx)
{
/* finalize stmt */
sqlite3_stmt ** p = (sqlite3_stmt **)ctx->stmt.ptr;
long cpt;
for(cpt = 0; cpt < ctx->nbStmt * 2; cpt++)
sqlite3_finalize(p[cpt]);
/* */
sqlite3_finalize(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Cursor);
sqlite3_finalize(ctx->sl3Begin);
sqlite3_finalize(ctx->sl3Commit);
sqlite3_finalize(ctx->sl3Rollback);
/* */
sqlite3_close(ctx->sl3Handle);
}
WAPIDECL long beginSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Begin);
if(sqlite3_step(ctx->sl3Begin) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long commitSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Commit);
if(sqlite3_step(ctx->sl3Commit) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long rollbackSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Rollback);
if(sqlite3_step(ctx->sl3Rollback) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long prepare_rwSl3(env * e, modCtxSl3 * ctx, char * table)
{
/*
confTable<1,x> = nom table
confTable<2,x> = nom colonne de la PK, dans l'ordre, separees par ","
confTable<3,x> = type de la colonne de la PK, lie avec confTable<2,x>
confTable<4,x> = nom de toutes les colonnes de la table, dans l'ordre, separees par ","
confTable<5,x> = type de toutes les colonnes de la table, dans l'ordre, lie avec confTable<4,x>
stmt[(x-1)*2] et stmt[(x-1)*2+1] = read/write stmt
*/
sqlite3_stmt * sl3read, * sl3write;
/* */
sqlite3_finalize(ctx->sl3Request);
dynLet(e, &ctx->request, "PRAGMA table_info(?1);", 22);
/* cid;name;type;notnull;dfltvalue;pk
0;kcust;INTEGER;0;;1
1;kind;INTEGER;0;;2
2;ident;TEXT;0;;0 */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
if(sqlite3_bind_text(ctx->sl3Request, 1, table, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
/* */
long nb = 0, cpt = 0;
/* read */
dynSetLen(e, &ctx->pkfilter, 0);
dynSetLen(e, &ctx->colPk, 0);
dynSetLen(e, &ctx->colPkType, 0);
dynSetLen(e, &ctx->colAll, 0);
dynSetLen(e, &ctx->colAllType, 0);
dynLet(e, &ctx->request, "select * from ", 14);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " where ", DYN_LGNONE);
/* */
while(sqlite3_step(ctx->sl3Request) == SQLITE_ROW) // peut renvoyer == SQLITE_DONE si pas de ligne, ou == SQLITE_ROW pour chaque ligne, ou == SQLITE_ERROR en cas d'erreur
{
/* les numeros des colonnes sont en base 0 */
if(strcmp((const char *)sqlite3_column_text(ctx->sl3Request, 2), SQLITE_TYPE_TEXT) != 0) return SL3ERR_COLTYPE;
if(strcmp((const char *)sqlite3_column_text(ctx->sl3Request, 2), SQLITE_TYPE_INTEGER) != 0) return SL3ERR_COLTYPE;
/* */
nb++;
dynStoreSz(e, &ctx->colAll, sqlite3_column_int64(ctx->sl3Request, 0) + 1, DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE, ',', DYN_NONE);
dynStoreSz(e, &ctx->colAllType, sqlite3_column_int64(ctx->sl3Request, 0) + 1, DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 2), DYN_LGNONE, ',', DYN_NONE);
if(sqlite3_column_int64(ctx->sl3Request, 5) > 0) // si c'est une colonne de la PK
{
if(++cpt > 1)
dynConcatSz(e, &ctx->pkfilter, " and ", DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, " = ?", DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, Int32ToSz(cpt, FALSE, 0), DYN_LGNONE);
/* */
dynStoreSz(e, &ctx->colPk, sqlite3_column_int64(ctx->sl3Request, 5), DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE, ',', DYN_NONE);
dynStoreSz(e, &ctx->colPkType, sqlite3_column_int64(ctx->sl3Request, 5), DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 2), DYN_LGNONE, ',', DYN_NONE); // TEXT INTEGER
}
}
sqlite3_finalize(ctx->sl3Request);
// si reset avant finalize, on peut reutiliser la requete preparee (repartir des bind), sinon il faut la preparer a nouveau ; reset => bind => step
if(cpt > 0)
{
dynConcat(e, &ctx->request, &ctx->pkfilter);
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &sl3read, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
}
else
return SL3ERR_NOPK;
/* */
dynLet(e, &ctx->request, "REPLACE INTO ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, (char *)table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " (", DYN_LGNONE);
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, ") VALUES (", DYN_LGNONE);
for(long i = 1; i <= nb; i++)
{
dynConcatSz(e, &ctx->request, i > 1 ? ",?" : "?", DYN_LGNONE);
dynConcatSz(e, &ctx->request, Int32ToSz(i, FALSE, 0), DYN_LGNONE);
}
dynConcatSz(e, &ctx->request, ") where ", DYN_LGNONE);
dynConcat(e, &ctx->request, &ctx->pkfilter);
if(nb > 0)
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &sl3write, NULL) != SQLITE_OK)
{
sqlite3_finalize(sl3write);
return SL3ERR_PREPARE;
}
/* memo dans ctx */
if(nb > 0)
{
if(dynCtrl(e, &ctx->stmt, (ctx->nbStmt + 1) * 2 * sizeof(pointeur), TRUE))
{
sqlite3_finalize(sl3read);
sqlite3_finalize(sl3write);
return SL3ERR_MEM;
}
sqlite3_stmt ** p = (sqlite3_stmt **)ctx->stmt.ptr;
p[ctx->nbStmt * 2] = sl3read;
p[ctx->nbStmt * 2 + 1] = sl3write;
ctx->nbStmt++;
long pos = dynDcount(e, &ctx->confTable, cVM, 1, cFM) + 1;
dynStoreSz(e, &ctx->confTable, 1, pos, (char *)table, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 2, pos, ctx->colPk.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 3, pos, ctx->colPkType.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 4, pos, ctx->colAll.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 5, pos, ctx->colAllType.mPtr, DYN_LGNONE, cFM, cVM);
/* */
return OK;
}
else
return SL3ERR_NOTABLEINFO;
}
WAPIDECL void remove_rwSl3(env * e, modCtxSl3 * ctx, char * table)
{
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return;
sqlite3_stmt * stmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2]; // read
sqlite3_finalize(stmt);
stmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2 + 1]; // write
sqlite3_finalize(stmt);
dynStoreSz(e, &ctx->confTable, 1, posTable, "@", 1, cFM, cVM);
/* remplacer celle supprimee par la derniere dans confTable et stmt ?? */
}
WAPIDECL long getDescSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * desc)
{
/* renvoie la liste des colonnes/cles de la table si "preparee" */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_TABLENOTPREP;
/* */
dynSetLen(e, desc, 0);
dynField(e, &ctx->confTable, &ctx->request, 4, posTable, cFM, cVM, 1); // colonnes
dynStore(e, desc, 1, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 5, posTable, cFM, cVM, 1); // type
dynStore(e, desc, 2, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 2, posTable, cFM, cVM, 1); // colonnes PK
dynStore(e, desc, 3, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 3, posTable, cFM, cVM, 1); // colonnes PK type
dynStore(e, desc, 4, DYN_NONE, &ctx->request, cFM, DYN_NONE);
return OK;
}
WAPIDECL long readSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * key, Dynamic * record)
{
/* !! champs de key et record en VM !! */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
{
if(prepare_rwSl3(e, ctx, table) != OK)
return SL3ERR_PREPARERW;
posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_PREPARERW;
}
/* table prepare_rw ok ici, faire les bind sur la cle (au moins 1 colonne) */
sqlite3_stmt * readStmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2];
sqlite3_reset(readStmt);
/* */
dynField(e, &ctx->confTable, &ctx->colPkType, 3, posTable, cFM, cVM, 1); // type des colonnes de la PK
long pk, nbPk = dynDcount(e, &ctx->colPkType, ',', DYN_NONE, DYN_NONE);
if(nbPk == 0) return SL3ERR_NOPK;
for(pk = 1; pk <= nbPk; pk++)
{
dynField(e, &ctx->colPkType, &ctx->request, pk, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne de la PK
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, key, &ctx->request, pk, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_text(readStmt, 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, key, &ctx->request, pk, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_int64(readStmt, 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
int cr = sqlite3_step(readStmt);
if(cr == SQLITE_ROW)
{
dynSetLen(e, record, 0);
dynField(e, &ctx->confTable, &ctx->colAllType, 5, posTable, cFM, cVM, 1); // type des colonnes
long col, nbCol = dynDcount(e, &ctx->colAllType, ',', DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, &ctx->colAllType, &ctx->request, col, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
dynStoreSz(e, record, col, DYN_NONE, (char *)sqlite3_column_text(readStmt, col - 1), DYN_LGNONE, cVM, DYN_NONE);
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
dynStoreNumber(e, record, col, DYN_NONE, sqlite3_column_int64(readStmt, col - 1), cVM, DYN_NONE);
else
return SL3ERR_COLTYPE;
}
return OK;
}
else if(cr == SQLITE_DONE)
return SL3ERR_NORECORD;
else if(cr == SQLITE_BUSY)
return SL3ERR_READLOCK;
else
return SL3ERR_STEP;
}
WAPIDECL long writeSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * record)
{
/* !! champs de record en VM !! */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
{
if(prepare_rwSl3(e, ctx, table) != OK)
return SL3ERR_PREPARERW;
posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_PREPARERW;
}
/* table prepare_rw ok ici, faire les bind sur la cle (au moins 1 colonne) */
sqlite3_stmt * writeStmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2 + 1];
sqlite3_reset(writeStmt);
/* */
dynField(e, &ctx->confTable, &ctx->colAllType, 5, posTable, cFM, cVM, 1); // type des colonnes
long col, nbCol = dynDcount(e, &ctx->colAllType, ',', DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, &ctx->colAllType, &ctx->request, col, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, record, &ctx->request, col, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_text(writeStmt, 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, record, &ctx->request, col, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_int64(writeStmt, 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
int cr = sqlite3_step(writeStmt);
if(cr == SQLITE_DONE)
return OK;
else if(cr == SQLITE_BUSY)
return SL3ERR_WRITELOCK;
else
return SL3ERR_STEP;
}
WAPIDECL long cursorSl3(env * e, modCtxSl3 * ctx, Dynamic * request, Dynamic * param)
{
/* param<1> = valeur champ (separateur VM) ; param<2> = type champ TEXT/INTEGER (separateur VM) */
sqlite3_finalize(ctx->sl3Cursor);
if(sqlite3_prepare_v2(ctx->sl3Handle, request->mPtr, -1, &ctx->sl3Cursor, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
/* binding */
dynField(e, param, &ctx->colAll, 1, DYN_NONE, cFM, DYN_NONE, 1);
dynField(e, param, &ctx->colAllType, 2, DYN_NONE, cFM, DYN_NONE, 1);
long col, nbCol = dynDcount(e, &ctx->colAllType, cVM, DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, param, &ctx->request, 2, col, cFM, cVM, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, param, &ctx->request, 1, col, cFM, cVM, 1); // valeur
if(sqlite3_bind_text(ctx->sl3Cursor, col - 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, param, &ctx->request, 1, col, cFM, cVM, 1); // valeur
if(sqlite3_bind_int64(ctx->sl3Cursor, col - 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
return OK;
}
WAPIDECL long fetchSl3(env * e, modCtxSl3 * ctx, Dynamic * record, long count)
{
/* count = 0 => tout lire en une seule fois ; renvoi le nombre d'enregs lus ; SL3ERR_FETCH si erreur */
dynSetLen(e, record, 0);
long nb = 0, cols, cpt;
int cr;
while((cr = sqlite3_step(ctx->sl3Cursor)) == SQLITE_ROW && (count == 0 || nb < count))
{
nb++;
/* remplir le record avec les donnees de la ligne */
cols = sqlite3_column_count(ctx->sl3Cursor); // si besoin : strcpy(s, sqlite3_column_name(ctx->sl3Request, 0));
for(cpt = 0; cpt < cols; cpt++)
dynStoreSz(e, record, nb, cpt + 1, (char *)sqlite3_column_text(ctx->sl3Cursor, cpt), DYN_LGNONE, cFM, cVM);
}
if(cr != SQLITE_DONE && cr != SQLITE_ROW)
return SL3ERR_FETCH;
else
return nb;
}
WAPIDECL long createTableSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * colName, Dynamic * colType, long nbPk)
{
sqlite3_finalize(ctx->sl3Request);
/* exemple
CREATE TABLE ftest (kcust INTEGER, kind INTEGER, ident TEXT,
CONSTRAINT ftrans_pk PRIMARY KEY (kcust,kind));
*/
/* colName et colType en VM, separateur = ',' ; type = TEXT/INTEGER */
dynLet(e, &ctx->request, "CREATE TABLE ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " (", DYN_LGNONE);
long col, nbCol = dynDcount(e, colName, ',', DYN_NONE, DYN_NONE);
if(nbCol <= 0)
return SL3ERR_NOTABLEINFO;
if(nbPk <= 0 || nbPk > nbCol)
return SL3ERR_NOPK;
for(col = 1; col <= nbCol; col++)
{
dynField(e, colName, &ctx->colAll, col, DYN_NONE, ',', DYN_NONE, 1);
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, " ", DYN_LGNONE);
dynField(e, colType, &ctx->colAllType, col, DYN_NONE, ',', DYN_NONE, 1);
dynConcat(e, &ctx->request, &ctx->colAllType);
if(col > 1)
dynConcatSz(e, &ctx->request, ",", DYN_LGNONE);
}
/* les <nbPk> premieres colonnes sont la cle primaire, dans l'ordre */
dynConcatSz(e, &ctx->request, ", CONSTRAINT ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, "_pk PRIMARY KEY (", DYN_LGNONE);
dynField(e, colName, &ctx->colAll, col, DYN_NONE, ',', DYN_NONE, nbPk); // les <nbPk> premieres colonnes sont la cle primaire, dans l'ordre
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, "))", DYN_LGNONE);
/* */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
int cr = sqlite3_step(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Request);
if(cr == SQLITE_DONE)
return OK;
else
return SL3ERR_STEP;
}
WAPIDECL long removeTableSl3(env * e, modCtxSl3 * ctx, char * table)
{
remove_rwSl3(e, ctx, table);
/* */
sqlite3_finalize(ctx->sl3Request);
dynLet(e, &ctx->request, "DROP TABLE ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
/* */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
int cr = sqlite3_step(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Request);
if(cr == SQLITE_DONE)
return OK;
else
return SL3ERR_STEP;
}
/*
1 base = 1 fichier sur disque (rm pour supprimer la base...), open ouvre ou cree la base (il suffit de verifier si le fichier existe...). Encodage = UTF-8
pas d'asynchrone (creer des threads/process) ; PRAGMA table_info(<table>) donne les infos sur une table (colonnes, types, PK etc.) ; pas de notion de schema (tout est dans la meme "base")
syntaxe pour binding dans requetes : ?1 ?2 ou :param1 $param2 @param3
docs : https://sqlite.org/capi3ref.html
sqlite3.c: The SQLite amalgamation source file
sqlite3.h: The header file that accompanies sqlite3.c and defines the C-language interfaces to SQLite.
shell.c: The command-line interface program itself.
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -lm -o sqlite3
gcc -fPIC -shared sqlite3.c -o libsqlite3.so -lpthread -ldl -lm
*/
+79
View File
@@ -0,0 +1,79 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include <libssh/libssh.h>
#include <libssh/sftp.h>
/* codes a passer a la fonction setError */
enum {
WSSH_MEM_ERROR = -2,
WSSH_ERROR = -1,
WSSH_OK = 0,
WSSH_SESSION = 1,
WSSH_SESSION_CONNECT = 2,
WSSH_AUTH = 3,
WSSH_CHANNEL = 4,
WSSH_CHANNEL_OPEN = 5,
WSSH_WRITE = 6,
WSSH_READ = 7,
WSSH_EXEC = 8,
WSSH_MODE = 9,
WSSH_SFTP = 10,
WSSH_SFTP_INIT = 11
};
enum {
WSSH_EXEC_MODE = 1,
WSSH_TERMINAL_MODE = 0
};
typedef struct {
ssh_session session;
ssh_channel channel; /* commandes console */
sftp_session sftp;
/* */
int err; /* erreur specifique au module */
int packet; /* taille des paquets lus un par un */
int execMode; /* TRUE si channelExec, FALSE si pseudo terminal */
} modContextSsh;
WAPIDECL void initSsh(env * e, modContextSsh * ctx);
WAPIDECL void freeSsh(env * e, modContextSsh * ctx);
WAPIDECL long setSession(env * e, modContextSsh * ctx, Dynamic * host, Dynamic * user, Dynamic * pwd);
WAPIDECL void freeSession(env * e, modContextSsh * ctx);
WAPIDECL long setChannel(env * e, modContextSsh * ctx, int mode);
WAPIDECL void freeChannel(env * e, modContextSsh * ctx);
WAPIDECL long channelExec(env * e, modContextSsh * ctx, Dynamic * data, Dynamic * resultat, number timeout);
WAPIDECL long channelWrite(env * e, modContextSsh * ctx, Dynamic * data);
WAPIDECL long channelRead(env * e, modContextSsh * ctx, Dynamic * data, number timeout);
/* faire idem channel pour "transfert" (sftp) */
WAPIDECL long setSftp(env * e, modContextSsh * ctx);
WAPIDECL void freeSftp(env * e, modContextSsh * ctx);
+288
View File
@@ -0,0 +1,288 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
#include "ssh.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextSsh ctxSsh;
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_WSSH_SESSION = 1,
EXMOD_WSSH_CHANNEL = 2,
EXMOD_WSSH_SFTP = 3,
EXMOD_WSSH_WRITECHANNEL = 4,
EXMOD_WSSH_EXECCHANNEL = 5,
EXMOD_WSSH_READCHANNEL = 6,
EXMOD_NB = 6
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Opening ssh session error",
"Opening ssh channel error",
"Opening sftp session error",
"Write channel error",
"Execute channel command error", // 5
"Read channel error"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
initSsh(e, &p_etat->ctxSsh);
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
freeSsh(e, &p_etat->ctxSsh);
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "openSession", 11))
{
/* get param in the right order */
var * paramHost = getParam(e, "host", 4);
var * paramUsername = getParam(e, "username", 8);
var * paramPassword = getParam(e, "password", 8);
/* ouvre la connexion ssh au serveur */
if(paramHost == NULL || paramUsername == NULL || paramPassword == NULL)
exc = EX_MODPARAM;
else if(paramHost->type != VAR_DYNAMIC || paramUsername->type != VAR_DYNAMIC || paramPassword->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(setSession(e, &p_etat->ctxSsh, paramHost, paramUsername, paramPassword) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SESSION);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "endSession", 10))
{
/* ferme la connexion ssh au serveur */
freeSession(e, &p_etat->ctxSsh);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "execChannel", 11))
{
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
var * paramResponse = getParam(e, "response", 8);
var * paramTimeout = getParam(e, "timeout", 7);
/* envoi d'une commande "one shot", pas besoin du 'openChannel' ici, lecture du resultat avec 'readChannel' et renvoi du resultat dans response, timeout en sec. dans timeout */
if(paramCommand == NULL || paramResponse == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if(var_conv_num(e, paramTimeout, &timeout))
{
if(paramResponse->type != VAR_DYNAMIC)
var_let(e, paramResponse, &e->int_dynamic, FALSE, FALSE);
if(channelExec(e, &p_etat->ctxSsh, paramCommand, paramResponse, timeout) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_EXECCHANNEL);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "openChannel", 11))
{
/* ouvre un canal de type "terminal" avec le serveur
faire un 'readChannel' la premiere fois apres le 'openChannel', puis enchainer les ecritures (commandes) et lectures (resultat) */
if(setChannel(e, &p_etat->ctxSsh, WSSH_TERMINAL_MODE) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_CHANNEL);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "writeChannel", 12))
{
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
if(paramCommand == NULL)
exc = EX_MODPARAM;
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* envoi d'une commande au pseudo-terminal */
if(channelWrite(e, &p_etat->ctxSsh, paramCommand) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_WRITECHANNEL);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "readChannel", 11))
{
/* get param in the right order */
var * paramResponse = getParam(e, "response", 8);
var * paramTimeout = getParam(e, "timeout", 7);
if(paramResponse == NULL || paramTimeout == NULL)
exc = EX_MODPARAM;
else if(paramResponse->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
/* lecture du resultat d'une commande (stdout dans paramResponse) en mode terminal, timeout en sec. dans timeout */
number timeout;
if(var_conv_num(e, paramTimeout, &timeout))
{
if(channelRead(e, &p_etat->ctxSsh, paramResponse, timeout) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_READCHANNEL);
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeChannel", 12))
{
/* ferme le channel mais laisse la connexion au serveur ouverte (mode terminal seulement, inutile en mode exec) */
freeChannel(e, &p_etat->ctxSsh);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "openSftp", 8))
{
/* ouvre un canal de type "transfert" avec le serveur */
if(setSftp(e, &p_etat->ctxSsh) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SFTP);
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeSftp", 9))
{
/* ferme le canal "transfert" mais laisse la connexion au serveur ouverte */
freeSftp(e, &p_etat->ctxSsh);
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+292
View File
@@ -0,0 +1,292 @@
/* **********************************************
__ __ __
\ \/ \/ / 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"
#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 */
}
/* ****** 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);
}
/* */
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;
}
}
+276 -313
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,157 +25,204 @@
#include <time.h>
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#else
#include "windows.h" // TODO ici
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#ifdef WINLIB
#include "windows.h"
#else
#include <sys/utsname.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_SYSTEM_FICTMP 1
#define EXMOD_SYSTEM_UNKNOWNVARENV 2
#define EXMOD_SYSTEM_SETENV 3
#define EXMOD_SYSTEM_UNSETENV 4
#define EXMOD_SYSTEM_GETHOST 5
#define EXMOD_SYSTEM_UNAME 6
#define EXMOD_SYSTEM_FORK 7
enum {
EXMOD_SYSTEM_FICTMP = 1,
EXMOD_SYSTEM_UNKNOWNVARENV = 2,
EXMOD_SYSTEM_SETENV = 3,
EXMOD_SYSTEM_UNSETENV = 4,
EXMOD_SYSTEM_UNAME = 5,
EXMOD_NB = 5
};
/* 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
};
/* ============================================================================================= */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#include "mod.c"
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// execute(command, returning, capturing)
// getEnv(nom, valeur)
// setEnv(nom, valeur, overwritting)
// getOS(nom) => int uname(struct utsname *buf);
// getHostname(nom, ip) => int uname(struct utsname *buf);
// TODO prevoir un mecanisme de securite, pour autoriser ou non certains fonctions dangereuses (execute, setenv)
//
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
if(p_etat == NULL)
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(p_etat == NULL)
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
exc = EX_MODETAT;
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "execute", 7) == 0)
else if(modFnIs(e, "execute", 7))
{
p_etat->error = 0;
// execute(command, returning, capturing)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(!param1 || param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramCommand = getParam(e, "command", 7);
var * paramReturnCode = getParam(e, "returnCode", 10);
var * paramCapturing = getParam(e, "capturing", 9);
if(paramCommand == NULL || paramReturnCode == NULL)
exc = EX_MODPARAM;
else if(!param2 || param2->type != VAR_NUMBER)
else if(paramCommand->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
int cr, flagCapturing = (param3 != NULL);
if(paramReturnCode->type != VAR_NUMBER)
var_let(e, paramReturnCode, &e->int_number, FALSE, FALSE);
/* */
int cr, flagCapturing = (paramCapturing != NULL);
if(flagCapturing)
{
if(param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
}
if(flagCapturing && exc == OK)
{
dynSetLen(e, param3, 0);
if(paramCapturing->type != VAR_DYNAMIC)
var_let(e, paramCapturing, &e->int_dynamic, FALSE, FALSE);
/* */
dynSetLen(e, paramCapturing, 0);
#ifdef WINLIB
if (!GetTempPathA(param3->mLgmax, param3->mPtr))
exc = EXMOD_SYSTEM_FICTMP;
else if(!GetTempFileNameA(param3->mPtr, "tmp", 0, e->int_dynamic.mPtr))
exc = EXMOD_SYSTEM_FICTMP;
long lg;
if( ! (lg = GetTempPathA(paramCapturing->mLgmax, paramCapturing->mPtr)))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
{
if(lg > paramCapturing->mLgmax)
{
if(dynCtrl(e, paramCapturing, lg, DYN_FALSE) == DYN_OK)
{
if( ! (lg = GetTempPathA(paramCapturing->mLgmax, paramCapturing->mPtr)))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
}
else
exc = EX_MEM;
}
if(exc == OK)
{
dynSetLen(e, paramCapturing, lg);
if(dynCtrl(e, &e->int_dynamic, MAX_PATH, DYN_FALSE) == DYN_OK)
{
if( ! GetTempFileNameA(paramCapturing->mPtr, "tmp", 0, e->int_dynamic.mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
dynSetLen(e, &e->int_dynamic, strlen(e->int_dynamic.mPtr));
}
else
exc = EX_MEM;
}
}
#else
int fd; // pour avoir un nom de fichier temporaire
dynLet(e, &e->int_dynamic, "/tmp/cap_XXXXXX", 15);
if((fd = mkstemp(e->int_dynamic.mPtr)) == -1)
exc = EXMOD_SYSTEM_FICTMP;
exc = setError(p_etat, EXMOD_SYSTEM_FICTMP);
else
close(fd);
#endif
@@ -184,308 +231,224 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
{
if(flagCapturing)
{
dynIns(e, &e->int_dynamic, 1, DYN_NONE, param3, '>', DYN_NONE);
cr = system(param1->mPtr);
dynRead(e, param3, e->int_dynamic.mPtr);
// TODO : purge fichier temp ?
dynSetAs(e, paramCapturing, paramCommand);
dynIns(e, paramCapturing, 1 + dynDcount(e, paramCapturing, '>', DYN_NONE, DYN_NONE), DYN_NONE, &e->int_dynamic, '>', DYN_NONE);
cr = system(paramCapturing->mPtr);
dynRead(e, paramCapturing, e->int_dynamic.mPtr);
remove(e->int_dynamic.mPtr); // purge fichier temp
}
else
{
cr = system(param1->mPtr);
cr = system(paramCommand->mPtr);
}
param2->num = cr * NUM_FACTEUR;
paramReturnCode->num = cr * NUM_FACTEUR;
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getEnv", 6) == 0)
else if(modFnIs(e, "getEnv", 6))
{
p_etat->error = 0;
/* utilisation de dynRead qui fait le travail */
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
var * paramValue = getParam(e, "value", 5);
if(paramVarName == NULL || paramValue == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
char * varenv = getenv(param1->mPtr);
if(!varenv)
exc = EXMOD_SYSTEM_UNKNOWNVARENV;
if(paramValue->type != VAR_DYNAMIC)
var_let(e, paramValue, &e->int_dynamic, FALSE, FALSE);
char * varenv = getenv(paramVarName->mPtr);
if(varenv == NULL)
exc = setError(p_etat, EXMOD_SYSTEM_UNKNOWNVARENV);
else
{
int lg;
if(dynCtrl(e, param2, (lg = strlen(varenv)), DYN_FALSE) == DYN_OK)
dynLet(e, param2, varenv, lg);
if(dynCtrl(e, paramValue, (lg = strlen(varenv)), DYN_FALSE) == DYN_OK)
dynLet(e, paramValue, varenv, lg);
else
exc = EX_MEM;
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "createEnv", 9) == 0)
else if(modFnIs(e, "createEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
var * paramValue = getParam(e, "value", 5);
if(paramVarName == NULL || paramValue == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
// verifier si existe avec getenv, si oui erreur
char * varenv = getenv(param1->mPtr);
char * varenv = getenv(paramVarName->mPtr);
if(varenv)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
else if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
else if (!SetEnvironmentVariableA(paramVarName->mPtr, paramValue->mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = setenv(param1->mPtr, param2->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
int cr = setenv(paramVarName->mPtr, paramValue->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "updateEnv", 9) == 0)
else if(modFnIs(e, "updateEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
var * paramValue = getParam(e, "value", 5);
if(paramVarName == NULL || paramValue == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(paramVarName->type != VAR_DYNAMIC || paramValue->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
if (!SetEnvironmentVariableA(paramVarName->mPtr, paramValue->mPtr))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = setenv(param1->mPtr, param2->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
int cr = setenv(paramVarName->mPtr, paramValue->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "deleteEnv", 9) == 0)
else if(modFnIs(e, "deleteEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramVarName = getParam(e, "varName", 7);
if(paramVarName == NULL)
exc = EX_MODPARAM;
else if(paramVarName->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, NULL))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
if (!SetEnvironmentVariableA(paramVarName->mPtr, NULL))
exc = setError(p_etat, EXMOD_SYSTEM_SETENV);
#else
int cr = unsetenv(param1->mPtr); // suppression
int cr = unsetenv(paramVarName->mPtr); // suppression
if(cr != 0)
{
exc = EXMOD_SYSTEM_UNSETENV;
setError(p_etat, cr);
}
exc = setError(p_etat, EXMOD_SYSTEM_UNSETENV);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getOS", 5) == 0)
else if(modFnIs(e, "getOS", 5))
{
p_etat->error = 0;
// uname() donne les infos
if(param1->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramOScode = getParam(e, "OScode", 6);
if(paramOScode == NULL)
exc = EX_MODPARAM;
else
{
if(paramOScode->type != VAR_DYNAMIC)
var_let(e, paramOScode, &e->int_dynamic, FALSE, FALSE);
#ifdef WINLIB
dynLet(e, param1, "Windows", DYN_LGNONE);
dynLet(e, paramOScode, "Windows", DYN_LGNONE);
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
{
if(dynCtrl(e, param1, (lg = strlen(name.sysname)), DYN_FALSE) == DYN_OK)
dynLet(e, param1, name.sysname, lg);
if(dynCtrl(e, paramOScode, (lg = strlen(name.sysname)), DYN_FALSE) == DYN_OK)
dynLet(e, paramOScode, name.sysname, lg);
else
exc = EX_MEM;
}
else
{
exc = EXMOD_SYSTEM_UNAME;
setError(p_etat, errno);
}
exc = setError(p_etat, EXMOD_SYSTEM_UNAME);
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getHostname", 5) == 0)
else if(modFnIs(e, "sendSignal", 10))
{
p_etat->error = 0;
// uname() donne les infos
if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
/* get param in the right order */
var * paramPid = getParam(e, "pid", 3);
var * paramSignalNumber = getParam(e, "signalNumber", 12);
if(paramPid == NULL || paramSignalNumber == NULL)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
DWORD size = param1->mLgmax;
if (!GetComputerNameA(param1->mPtr, &size))
number pid, numSignal;
if( var_conv_num(e,paramPid, &pid) && var_conv_num(e, paramSignalNumber, &numSignal) )
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
pid /= NUM_FACTEUR;
numSignal /= NUM_FACTEUR;
#ifdef WINLIB
// faire differemment sous windows : pas de kill dispo, passer par des evenements (GenerateConsoleCtrlEvent ne fonctionne pas si autre session/cmd/BACK...)
#define SIGINT 2
#define SIGUSR1 10
#define SIGTERM 15
// autoriser tous les process a inter agir...
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
//
HANDLE hEvent = NULL;
char eventName[40] = {0};
if(numSignal == SIGTERM || numSignal == SIGINT)
{
sprintf(eventName, "Global\\wterm%lld", pid);
hEvent= CreateEvent(&sa, FALSE, FALSE, eventName);
}
else if(numSignal == SIGUSR1)
{
sprintf(eventName, "Global\\wdebug%lld", pid);
hEvent = CreateEvent(&sa, FALSE, FALSE, eventName);
}
if(hEvent != NULL) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur : l'event existe deja (et hEvent n'est pas NULL)
{
// envoyer le signal
SetEvent(hEvent);
CloseHandle(hEvent);
}
//
#else
if(numSignal == SIGTERM || numSignal == SIGINT || numSignal == SIGUSR1)
kill(pid, numSignal);
#endif
}
else
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
if (gethostname(param2->mPtr, param2->mLgmax) == SOCKET_ERROR)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
struct hostent * host_entry;
host_entry = gethostbyname(param2->mPtr);
if (host_entry == NULL)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
dynLet(e, param2, inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]), DYN_LGNONE);
WSACleanup();
}
}
}
}
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
{
if(dynCtrl(e, param1, (lg = strlen(name.nodename)), DYN_FALSE) == DYN_OK)
{
dynLet(e, param1, name.nodename, lg);
// lecture ip
struct hostent * host = gethostbyname(param1->mPtr);
if(host)
{
dynLet(e, param2, inet_ntoa(*(struct in_addr *)host->h_addr_list[0]), DYN_LGNONE);
}
else
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, h_errno);
}
}
else
exc = EX_MEM;
}
else
{
setError(p_etat, errno);
exc = EXMOD_SYSTEM_UNAME;
}
#endif
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "fork", 4) == 0)
else if(modFnIs(e, "sleep", 5))
{
p_etat->error = 0;
#ifndef UNIX
// faire differemment sous windows : pas de fork dispo ? CreateProcess()
#else
pid_t fils = fork();
if(fils == -1)
/* get param in the right order */
var * paramDuration = getParam(e, "duration", 8);
if(paramDuration == NULL)
exc = EX_MODPARAM;
else if(paramDuration->type != VAR_DYNAMIC && paramDuration->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
number duration;
if(var_conv_num(e, paramDuration, &duration))
{
exc = EXMOD_SYSTEM_FORK;
setError(p_etat, errno);
#ifdef WINLIB
// duree attente envoyee en secondes
Sleep(duration * 1000 / NUM_FACTEUR); // en millisec.
#else
// duree attente envoyee en secondes, avec les decimales
usleep(duration * (1000000 / NUM_FACTEUR)); // en microsec.
#endif
}
else
{
if(fils == 0)
e->ppid = 0; // process fils
else
e->ppid = fils; // process pere
}
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "wait", 4) == 0)
{
#ifndef UNIX
// faire differemment sous windows : pas de wait dispo ? WaitForSingleObject()
#else
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
param1->num = waitpid(-1, NULL, WNOHANG) * NUM_FACTEUR; // renvoi le pid d'un fils qui s'est fini, 0 si pas de fils termine
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "kill", 4) == 0)
{
#ifndef UNIX
// faire differemment sous windows : pas de kill dispo ?
#else
kill(0, SIGTERM); // envoi un signal de fin a tous les fils
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "sleep", 5) == 0)
{
#ifdef WINLIB
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
// duree attente envoyee en secondes
Sleep(param1->num * 1000 / NUM_FACTEUR); // en millisec.
#else
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
// duree attente envoyee en secondes, avec les decimales
usleep(param1->num * (1000000 / NUM_FACTEUR)); // en microsec.
#endif
}
/* ----------------------------------------------------------------------------------------------- */
/* ============================================================================================= */
else
{
setError(p_etat, 0);
exc = EX_MODFUNC; // fonction non prise en charge
exc = EX_MODFUNC; /* unsupported function */
}
//
return exc;
}
+175
View File
@@ -0,0 +1,175 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* ============================================================================================= */
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
#define MOD_VERSION 1
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
enum {
EXMOD_xxx = 1,
EXMOD_NB = 1
};
/* libelles des codes d'erreur, qui doivent aller de 1 a EXMOD_NB */
char * descModErr[] = {
"No error", // 0
"Template error"
};
/* ============================================================================================= */
#include "mod.c"
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
/* init/end/vers/error sont obligatoires pour tout module */
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
if(p_etat == NULL)
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
setError(p_etat, OK); // evite un warning de compil
//*** code specifique ici
/* ============ here ============ */
}
}
/* ne rien faire si deja un etat (rappels d'init ne font rien) */
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
/* ============ here ============ */
// liberation du module avant arret process
memfree(e, p_etat);
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
else if(modFnIs(e, "vers", 4))
{
var * paramVersion = getParam(e, "version", 7);
if(paramVersion == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module
if(paramVersion->type == VAR_DYNAMIC)
dynLet(e, paramVersion, Int32ToSz(MOD_VERSION, FALSE, 0), DYN_LGNONE);
else if(paramVersion->type == VAR_NUMBER)
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
else
{
var_let(e, paramVersion, &e->int_number, FALSE, FALSE);
paramVersion->num = (ent64)(MOD_VERSION * NUM_FACTEUR);
}
}
}
else if(modFnIs(e, "error", 5))
{
/* renvoie la derniere erreur specifique au module*/
var * paramModError = getParam(e, "modError", 8);
var * paramModErrorDescription = getParam(e, "modErrorDescription", 19); /* facultatif */
if(paramModError == NULL)
exc = EX_MODPARAM;
else
{
// renvoie le dernier code erreur specifique du module
if(paramModError->type == VAR_DYNAMIC)
dynLet(e, paramModError, Int32ToSz(p_etat->error, FALSE, 0), DYN_LGNONE);
else if(paramModError->type == VAR_NUMBER)
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
{
var_let(e, paramModError, &e->int_number, FALSE, FALSE);
paramModError->num = (ent64)(NUM_FACTEUR * p_etat->error);
}
if(paramModErrorDescription != NULL)
{
if(paramModErrorDescription->type != VAR_DYNAMIC)
var_let(e, paramModErrorDescription, &e->int_dynamic, FALSE, FALSE);
dynSetLen(e, paramModErrorDescription, 0);
if(p_etat->error >= 0 && p_etat->error <= EXMOD_NB)
dynLet(e, paramModErrorDescription, descModErr[p_etat->error], DYN_LGNONE);
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "xxx", 3))
{
/* get param in the right order */
var * param = getParam(e, "xxxParam", 8);
if(param == NULL)
exc = EX_MODPARAM;
else if(param->type != VAR_DYNAMIC && param->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
number x;
if(var_conv_num(e, param, &x))
exc = OK;
else
exc = setError(p_etat, EXMOD_xxx);
}
}
/* ============================================================================================= */
else
{
exc = EX_MODFUNC; /* unsupported function */
}
return exc;
}
+83
View File
@@ -0,0 +1,83 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
/* programme de test unitaire de lib/fonctions */
/* gcc w_src/test.c -s -o exec/test -Wall -m64 -DUNIX -L./exec -l:libw.so -l:cipher_lib.so */
#include "convert.h"
#include "cipher.h"
env e;
modContextCipher ctx;
int main(int argc, char * argv[])
{
init_env(&e);
//
Dynamic v, w, x;
dynInit(&e, &v, DYN_LGMIN);
dynInit(&e, &w, DYN_LGMIN);
dynInit(&e, &x, DYN_LGMIN);
//
dynLet(&e, &v, "test des encodages12", DYN_LGNONE);
printf("test base64: %s\n", v.mPtr);
//str2hex(&e, &v, &w);
str2base64(&e, &v, &w);
printf("%s\n", w.mPtr);
dynLet(&e, &v, "dGVzdCBkZXMgZW5jb2RhZ2VzMTI=", DYN_LGNONE);
base642str(&e, &v, &w);
printf("decodage: %s\n", w.mPtr);
dynLet(&e, &v, "303132333435363738394142434445", DYN_LGNONE);
hex2str(&e, &v, &w);
printf("hexa2str: %s\n", w.mPtr);
//
dynLet(&e, &v, "x#11yugjh#HDxxx", DYN_LGNONE);
long cr = dynEscapeHexaMark(&e, &v);
printf("escape hexamark (cr %ld): *%s* lg %lld\n", cr, v.mPtr, v.mLg);
//
cipherInit(&e, &ctx);
dynLet(&e, &x, "cle1234567890123", DYN_LGNONE);
dynLet(&e, &v, "ABCDEFGHIJKLMNOP123456", DYN_LGNONE);
printf("\ncipher_aes128: %s cle: %s\n", v.mPtr, x.mPtr);
cr = cipher_AES128(&e, &ctx, &x, &v, &w);
printf("lg chiffre: %lld cr:%ld\n", w.mLg, cr);
dynSetLen(&e, &v, 0);
cr = decipher_AES128(&e, &ctx, &x, &w, &v);
printf("decipher_aes128 (lg: %lld): *%s* cr:%ld\n", v.mLg, v.mPtr, cr);
cipherEnd(&e, &ctx);
//
dynFree(&e, &v);
dynFree(&e, &w);
dynFree(&e, &x);
//
return 0;
}
+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);
+270 -643
View File
File diff suppressed because it is too large. Load diff
+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;
}
+176 -18
View File
@@ -29,7 +29,16 @@
#include "var.h"
#include "hashtable.h"
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
{
/* ne pas regarder le type precedent : ecraser ! */
if(v == NULL)
@@ -55,7 +64,7 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
v->lg = 0;
v->lgmax = sep_lgm;
v->ptr[0] = 0;
v->codePage = CP_DEFAULT;
v->codePage = WCP_DEFAULT;
}
break;
case VAR_BUFFER:
@@ -102,23 +111,130 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
}
}
void var_ctrl_param(env * e, var * v)
// obsolete
//WAPIDECL int varptrtbl_ctrl(env * e, var * v)
//{
// /* indique si la var "v" appartient a une var de type pointeur (TRUE) */
// if(v == NULL)
// return FALSE;
// if(v->type == VAR_PARAM)
// return FALSE;
// /*
// format de varptrtbl : toutes les entrees sont de 8 octets
// v[1] = nb, v[2] = ad var param, v[3] = ptr de la var param, v[4] = ad var param2, etc.
// */
// pointeur * beg = (pointeur *)e->varptrtbl.ptr;
// ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
// pointeur * curr = beg + 2;
// while(nb--)
// if((pointeur *)(*curr) == (pointeur *)v->ptr)
// return TRUE; // deja existant
// else
// curr += 2;
// // pas trouve
// return FALSE;
//}
//
//WAPIDECL void varptrtbl_maj(env * e, var * v)
//{
// // ajoute a e->varptrtbl la var si de type "pointeur" : VAR_PARAM, objet...
// if(v == NULL)
// return;
// if(v->type != VAR_PARAM)
// return;
// /*
// format de varptrtbl : toutes les entrees sont de 8 octets
// v[1] = nb, v[2] = ad var param, v[3] = ptr de la var param, v[4] = ad var param2, etc.
// */
// pointeur * beg = (pointeur *)e->varptrtbl.ptr;
// ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
// pointeur * curr = ++beg;
// ent64 addnb = nb + 1;
// while(nb--)
// if((pointeur *)(*curr) == (pointeur *)v)
// {
// curr++;
// *curr = (pointeur)v->ptr;
// return; // deja existant : maj ptr vraie var
// }
// else
// curr += 2;
// // pas trouve : ajout a la fin
// if(dynCtrl(e, &e->varptrtbl, sizeof(pointeur) * addnb * 2 + 1, TRUE))
// {
// beg = (pointeur *)e->varptrtbl.ptr; // au cas ou realloc memoire
// *((ent64 *)beg) = addnb;
// curr = beg + addnb * 2;
// *curr-- = (pointeur)v->ptr;
// *curr = (pointeur)v;
// }
//}
//
//WAPIDECL void varptrtbl_del(env * e, var * v)
//{
// // supprime de e->varptrtbl la var param v
// if(v == NULL)
// return;
// /*
// format de varptrtbl : toutes les entrees sont de 8 octets
// v[1] = nb, v[2] = ad ptr, v[3] = ptr sur la var param, v[4] = ad ptr 2, etc.
// */
// pointeur * beg = (pointeur *)e->varptrtbl.ptr;
// ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
// pointeur * curr = ++beg;
// ent64 savnb = nb;
// while(nb--)
// if((pointeur *)(*curr) == (pointeur *)v)
// {
// // trouve : mettre le dernier a la place de celui en cours, sauf si c'est le dernier
// *((ent64 *)beg) = savnb - 1;
// if(nb > 0) // pas de swap a faire si c'est le dernier qui est supprime
// {
// beg += savnb * 2 - 1; // le dernier
// *curr++ = *beg++;
// *curr = *beg;
// }
// }
// else
// curr += 2;
// // pas trouve : RAS
//}
WAPIDECL int var_conv_num(env * e, var * v, number * num)
{
/* controle que la var "v", si de type PARAM, pointe sur une var toujours existante... */
if(v->type != VAR_PARAM)
return;
/* TODO lire e->par_ptr de type dynamic ??? */
/* dans le cas : hash, puis var de hash, puis clear hash : quid de la var de hash : ras car c'est une copie ! */
if(v == NULL || num == NULL)
return FALSE;
if(v->type == VAR_PARAM)
{
if((v = (var *)v->ptr) == NULL)
return FALSE;
}
if(v->type == VAR_NUMBER)
{
*num = v->num;
return TRUE;
}
if(v->type != VAR_DYNAMIC)
return FALSE;
/* convertir si string, en number */
*num = dynToNumber(e, v);
return(v->mInternal == DYN_OK);
}
void var_free(env * e, var * v, int suivre_par)
WAPIDECL void var_free(env * e, var * v, int suivre_par)
{
var * pvar;
/* */
if(v == NULL)
return;
if(suivre_par && v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* rien a liberer sur vars NULL, NUMBER et PARAM (ce dernier cas n'est pas possible) */
switch(v->type)
{
@@ -149,15 +265,27 @@ void var_free(env * e, var * v, int suivre_par)
v->type = VAR_NULL;
}
void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
{
var * pvar;
/* tient compte de la valeur precedente de la var ; suivre_let/suivre_v = TRUE pour travailler avec la var pointee */
/* ici correspondont a "let = v" */
/* ici correspond a "let = v" */
if(suivre_let && let->type == VAR_PARAM)
let = (var *)let->ptr; /* travailler avec la var pointee ! */
{
if((let = (var *)let->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
if(suivre_v && v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
// liberation variable affectee
var_free(e, let, TRUE);
// init et copie
@@ -173,7 +301,6 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
case VAR_DYNAMIC:
var_init(e, let, v->type, 0, v->lg + 1, NULL); // +1 pour le \0 de fin
memcopie(let->ptr, v->ptr, v->lg + 1); // permet de copier le \0 de fin
//memcpy(let->ptr, v->ptr, v->lg + 1);
let->lg = v->lg;
break;
//
@@ -183,12 +310,11 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
// boucler et copier les elements, attention aux cycles !
hashtable_select(e, v);
while(hashtable_next(e, v, e->nom, &pvar))
// TODO copie recursive + copie de la var "pvar"
hashtable_do(e, HASH_WRITE, let, e->nom, &pvar);
hashtable_do(e, HASH_WRITE, let, e->nom, &pvar); // WRITE appelle var_let : recursif de fait
break;
//
case VAR_PARAM:
if(!suivre_v)
if(!suivre_v) // ??
var_init(e, let, VAR_PARAM, 0, 0, v->ptr);
break;
@@ -198,4 +324,36 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
}
}
WAPIDECL void var_resize(env * e, var * v, ent64 mod_lgm, ent64 sep)
{
if(v == NULL)
{
e->exception = EX_NAVAR;
return;
}
if(v->type == VAR_PARAM)
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* */
if(v->type == VAR_DYNAMIC)
{
if(dynResize(e, v, mod_lgm) != DYN_OK)
e->exception = EX_NAVAR; /* erreur de resize, prevoir une erreur specifique ? */
}
else if(v->type == VAR_HASHTABLE)
{
var_free(e, v, FALSE);
var_init(e, v, VAR_HASHTABLE, mod_lgm, sep, NULL);
if(v->type != VAR_HASHTABLE)
e->exception = EX_NAVAR; /* erreur de resize, prevoir une erreur specifique ? */
}
else
e->exception = EX_NAVAR; /* resize uniquement de dynamic et hashtable, prevoir une erreur specifique ? */
}
/* ********************************************** */
+11 -4
View File
@@ -23,10 +23,17 @@
#ifndef VAR_H
#define VAR_H
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
void var_ctrl_param(env * e, var * v);
void var_free(env * e, var * v, int suivre_par);
void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
#include "apidecl.h"
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
WAPIDECL int var_conv_num(env * e, var * v, number * num);
WAPIDECL void var_free(env * e, var * v, int suivre_par);
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
WAPIDECL void var_resize(env * e, var * v, ent64 mod_lgm, ent64 sep);
WAPIDECL int varptrtbl_ctrl(env * e, var * v);
WAPIDECL void varptrtbl_maj(env * e, var * v);
WAPIDECL void varptrtbl_del(env * e, var * v);
/* ********************************************** */
#endif
+18
View File
@@ -0,0 +1,18 @@
set WBIN=exec
set WLIB=.
set WSRC=.
exec\lwc prg.w
exec\lwa prg.wa
exec\lw prg
rem
exec\lwc comp.w
exec\lwa comp.wa
exec\lw comp
rem
exec\lwc pdf.w
exec\lwa pdf.wa
exec\lw pdf
rem
exec\lwc debug.w
exec\lwa debug.wa
exec\lw debug 1234
+6 -3
View File
@@ -51,13 +51,13 @@ input: input
declare: declare
let: let
delet: delet ; unlet ??
delet: delet
new: new
class: class
this: this
parent: parent
free: free
hold: hold
precision: precision
setsep: setsep
@@ -66,6 +66,8 @@ frac: frac
abs: abs
neg: neg
round: round
sqrt: sqrt
exp: exp
type: type
len: len
@@ -74,6 +76,7 @@ dcount: dcount
field: field
index: index
search: search
sortedsearch: sortedsearch
change: change
format: format
insert: insert
@@ -101,7 +104,7 @@ ends: (1,1,#5D) ; ]
indirect: !
typeof: ? ; typeof ??
typeof: typeof ; typeof x.y.z
stringdq: (1,1,#22) (0,765,#20-#21#23-#EF) (1,1,#22) ; contenu chaine : car car car #FF (en majuscule), a verifier lors du parse (hexa -> binaire + controle)
stringq: (1,1,#27) (0,765,#20-#26#28-#EF) (1,1,#27) ; idem
+115
View File
@@ -0,0 +1,115 @@
<?php
/*************************************************************************************
* w.php
* -----
* Author: FDE
* Contributors:
* Copyright: (c) 2023
* Release Version: 1.0
* Date Started: 05/10/2024
*
* W language file for GeSHi.
*
* a mettre ici : /lamp0/web/vhosts/www.lanisys.fr/htdocs/wiki/vendor/geshi/geshi/src/geshi
*
*************************************************************************************
*
* This file is part of GeSHi.
*
* GeSHi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GeSHi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GeSHi; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
************************************************************************************/
$language_data = array (
'LANG_NAME' => 'W',
'COMMENT_SINGLE' => array(1 => ';'),
'COMMENT_MULTI' => array(),
'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,
'QUOTEMARKS' => array('"', '\''),
'ESCAPE_CHAR' => '',
'KEYWORDS' => array(
1 => array(
'begin', 'background', 'library', 'except', 'end', 'sub',
'endsub', 'include', 'loop', 'endloop', 'return', 'returnon',
'break', 'breakon', 'continue', 'continueon', 'throw', 'catch',
'foreach', 'in', 'like', 'if', 'then', 'elseif', 'else',
'endif', 'endfor','echo', 'echonl', 'input', 'nop', 'part', 'declare',
'let', 'do', 'call', 'invoke', 'delet', 'class', 'free',
'new', 'this', 'parent', 'precision', 'setsep'
),
2 => array(
'or', 'and', 'not', 'int', 'frac', 'abs', 'neg', 'type', 'typeof',
'tonum', 'tostring', 'count', 'len', 'format', 'dcount',
'round', 'field', 'index', 'search', 'change', 'insert', 'remove'
)
),
'SYMBOLS' => array(
'(', ')', '{', '}', '[', ']'
),
'CASE_SENSITIVE' => array(
GESHI_COMMENTS => false,
1 => true,
2 => true,
),
'STYLES' => array(
'KEYWORDS' => array(
1 => 'color: #b1b100; font-weight: bold;',
2 => 'color: #b1b100;'
),
'COMMENTS' => array(
1 => 'color: #666666; font-style: italic;',
),
'ESCAPE_CHAR' => array(
0 => 'color: #000099; font-weight: bold;'
),
'BRACKETS' => array(
0 => 'color: #000066;'
),
'STRINGS' => array(
0 => 'color: #009900;'
),
'NUMBERS' => array(
0 => 'color: #CC0000;'
),
'METHODS' => array(
1 => 'color: #006600;'
),
'SYMBOLS' => array(
0 => 'color: #000066;'
),
'REGEXPS' => array(
),
'SCRIPT' => array(
0 => '',
1 => '',
)
),
'URLS' => array(
1 => '',
2 => ''
),
'OOLANG' => false,
'OBJECT_SPLITTERS' => array(
1 => '\\'
),
'REGEXPS' => array(
),
'STRICT_MODE_APPLIES' => GESHI_NEVER,
'SCRIPT_DELIMITERS' => array(),
'HIGHLIGHT_STRICT_BLOCK' => array(
0 => false,
1 => false
)
);
+91
View File
@@ -0,0 +1,91 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
// --- gestion protocole websocket (http + protocole binaire specifique)
typedef struct {
int state; /* etat de decodage des trames http/ws : 0 entete a lire, 1 en cours lecture entete, 2 lecture corps websocket binaire */
ent64s lengthToRead; /* longueur de donnees (corps, frame header) restant a lire */
Dynamic header; /* liste des entetes http <1,x> nom entete (minuscule) <2, x> valeur, le decodage de la premiere ligne est mis ici : http_method http_path http_vers */
Dynamic content; /* corps du message binaire ws */
Dynamic contentControl; /* content control frame found in fragment */
Dynamic line, tmp; /* buffer de lecture d'une ligne, variable de travail */
Dynamic frameHeader; /* 14 octets utilises maxi */
int finalFrame, mask, opcode, len, fragment, opcodeFragment, controlInFragment;
octet maskey[4];
int error;
} modCtxWs;
enum {
/* state */
WSSTATE_HEADERTOREAD = 0,
WSSTATE_READINGHEADER = 1,
WSSTATE_READINGFRAMEHEADER = 2,
WSSTATE_READINGFRAMEHEADEREXT = 3,
WSSTATE_READINGFRAMECONTENT = 4,
/* codes d'erreur */
WS_METHOD_KO = 1,
WS_METHOD_VERSION_KO = 2,
WS_INCORRECT_LENGTH = 3,
WS_COLON_MISSING = 4,
WS_MISSING_HEADER = 5,
WS_MISSING_MASK = 6,
WS_OPCODE_KO = 7,
WS_FRAGMENT_KO = 8,
WS_LENGTH_TOO_HIGH = 9,
WS_MEMORY = 10,
/* code retour */
WS_REQUEST_ERROR = -1,
WS_REQUEST_INPROGRESS = 0,
WS_REQUEST_COMPLETE = 1,
WS_REQUEST_EXPECTCONTENT = 2,
WS_REQUEST_CLOSE = 3,
WS_REQUEST_PING = 4,
WS_REQUEST_PONG = 5,
WS_REQUEST_FRAGMENT = 6,
/* framing opcode */
WS_FRAME_OPCODE_TEXT = 1,
WS_FRAME_OPCODE_BINARY = 2,
WS_FRAME_OPCODE_CLOSE = 8,
WS_FRAME_OPCODE_PING = 9,
WS_FRAME_OPCODE_PONG = 10,
/* framing fragment */
WS_FRAME_FRAGMENT_ON = 0,
WS_FRAME_FRAGMENT_OFF = 1,
WS_FRAME_MASK_ON = 1,
WS_FRAME_MASK_OFF = 0
};
WAPIDECL void Init(env * e, modCtxWs * ctx);
WAPIDECL void End(env * e, modCtxWs * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxWs * ctx, Dynamic * data);
WAPIDECL long MakeExpectContent(env * e, modCtxWs * ctx, Dynamic * reponse);
WAPIDECL long MakeFrame(env * e, modCtxWs * ctx, int frameType, Dynamic * data, Dynamic * response);
+475
View File
@@ -0,0 +1,475 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "websocket.h"
#include "convert.h"
#include "hash.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
#define CRLF "\r\n"
#define LEN_CRLF 2
static int HeaderCheck(env * e, modCtxWs * ctx, char * headerName, char * headerValue)
{
long posEntete = dynLocateSz(e, &ctx->header, headerName, cVM, 1, cFM);
if(posEntete == DYN_NOTLOCATED)
return FALSE;
/* */
dynField(e, &ctx->header, &ctx->tmp, 1, posEntete, cFM, cVM, 1);
if(headerValue)
{
str2lower(e, &ctx->tmp);
return dynCompare(e, &ctx->tmp, CMP_EQ, headerValue, DYN_LGNONE);
}
else
return TRUE;
}
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxWs * ctx)
{
ctx->error = 0;
ctx->state = WSSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
ctx->fragment = FALSE; /* TRUE if fragmentation is on */
ctx->controlInFragment = FALSE;
dynInit(e, &ctx->header, DYN_LGMIN);
dynInit(e, &ctx->content, DYN_LGMIN);
dynInit(e, &ctx->contentControl, DYN_LGMIN);
dynInit(e, &ctx->line, DYN_LGMIN);
dynInit(e, &ctx->tmp, DYN_LGMIN);
dynInit(e, &ctx->frameHeader, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxWs * ctx)
{
dynFree(e, &ctx->header);
dynFree(e, &ctx->content);
dynFree(e, &ctx->contentControl);
dynFree(e, &ctx->line);
dynFree(e, &ctx->tmp);
dynFree(e, &ctx->frameHeader);
}
WAPIDECL long ExtractMessage(env * e, modCtxWs * ctx, Dynamic * data)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
if(ctx->state == WSSTATE_HEADERTOREAD || ctx->state == WSSTATE_READINGHEADER)
{
for(;;)
{
long ind = dynIndexSz(e, data, CRLF, LEN_CRLF, 1);
if(ind < 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
dynSetLen(e, &ctx->line, 0);
if(ind > 0)
dynSubstr(e, data, &ctx->line, 0, ind, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, ind + LEN_CRLF);
/* ici <ctx->line> contient la ligne d'entete et <data> est a jour avec les donnees suivantes */
/* */
if(ctx->state == WSSTATE_HEADERTOREAD)
{
/* premiere ligne du protocole */
dynField(e, &ctx->line, &ctx->tmp, 1, DYN_NONE, ' ', DYN_NONE, 1); // method
if(dynCompare(e, &ctx->tmp, CMP_NE, "GET", 3))
{
ctx->error = WS_METHOD_KO; /* seule GET autorisee */
return WS_REQUEST_ERROR; /* quand erreur, l'appelant doit vider le "conteneur" de donnee !? */
}
dynSetLen(e, &ctx->header, 0); // vider le header
dynInsSz(e, &ctx->header, 1, 1, "http_method", 11, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 2, DYN_NONE, ' ', DYN_NONE, 1); // path
dynInsSz(e, &ctx->header, 1, 1, "http_path", 9, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 3, DYN_NONE, ' ', DYN_NONE, 1);
if(ctx->tmp.mLg == 0)
{
ctx->error = WS_METHOD_KO; /* seule GET autorisee et version doit etre presente */
return WS_REQUEST_ERROR;
}
else
{
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
}
/* */
ctx->state = WSSTATE_READINGHEADER;
}
else
{
/* entetes a lire */
if(ctx->line.mLg == 0)
{
/* fin des entetes / entete typique ws =>
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
*/
dynSetLen(e, &ctx->content, 0);
if( ! HeaderCheck(e, ctx, "upgrade", "websocket"))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "connection", "upgrade"))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "host", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "origin", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "sec-websocket-version", "13"))
{
/* ici renvoyer une reponse 400 avec la valeur acceptee du serveur pour la version */
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "sec-websocket-key", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
/* ctx->tmp contient la clé codée en Base64 : calcul a faire pour renvoi au client */
dynConcatSz(e, &ctx->tmp, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36);
encodageSha1(e, &ctx->tmp, &ctx->line); // resultat en hexa ascii
hex2str(e, &ctx->line, &ctx->tmp); // binaire, à encoder en Base64
str2base64(e, &ctx->tmp, &ctx->line);
/* ajouter l'entete de reponse */
dynInsSz(e, &ctx->line, 1, DYN_NONE, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept:",
DYN_LGNONE, ' ', DYN_NONE);
dynConcatSz(e, &ctx->line, "\r\n\r\n", 4); /* fin de reponse http */
/* */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->lengthToRead = 2;
dynSetLen(e, &ctx->frameHeader, 0);
return WS_REQUEST_EXPECTCONTENT; /* envoyer la reponse (handshake) et attendre le contenu ws specifique */
}
else
{
/* lecture de l'entete */
dynBegin(e, &ctx->line);
if(dynNext(e, &ctx->line, &ctx->tmp, ':') > -1)
{
dynCut(e, &ctx->line, ctx->line.mInternal + 1);
// nom entete en minuscule
dynErase(e, &ctx->tmp, " ");
str2lower(e, &ctx->tmp);
if(dynLocateSz(e, &ctx->header, ctx->tmp.mPtr, cVM, 1, cFM) != DYN_NOTLOCATED)
continue; // entete deja memorisee, ignorer le doublon
// valeur
dynTrimSpace(e, &ctx->line);
// tmp = nom entete, line = valeur entete
dynIns(e, &ctx->header, 1, 1, &ctx->tmp, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->line, cFM, cVM);
}
else
{
/* erreur de syntaxe dans l'entete */
ctx->error = WS_COLON_MISSING;
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
}
}
} /* endless for */
}
/* */
/* a partir d'ici, une erreur provoque le retour a l'attente d'une entete de frame, pas d'entete html */
if(ctx->state == WSSTATE_READINGFRAMEHEADER)
{
/* lecture d'une requete WS : frame header 2 octets */
if(data->mLg == 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->frameHeader, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees d'entete sont lues, decodage de la frame */
dynConcatSz(e, &ctx->frameHeader, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
/* gerer la fragmentation ici (finalFrame), 1,2 ok, 8,9,10 possible au milieu mais non fragmente */
ctx->finalFrame = (ctx->frameHeader.ptr[0] & 1);
ctx->opcode = (ctx->frameHeader.ptr[0] >> 4);
/* fragment management */
if( ! ctx->fragment)
{
dynSetLen(e, &ctx->content, 0);
if(ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
; /* ras pas de fragmentation */
else if(ctx->opcode != WS_FRAME_OPCODE_TEXT && ctx->opcode != WS_FRAME_OPCODE_BINARY)
{
/* fragment non autorisee sur control frame ou opcode inconnu */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_FRAGMENT_KO;
return WS_REQUEST_ERROR;
}
else
{
/* debut de fragment */
ctx->fragment = TRUE;
ctx->opcodeFragment = ctx->opcode;
}
}
else
{
/* fragmentation en cours */
if(ctx->opcode == 0)
{
/* ras fragment suite ou fin */
if(ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
ctx->fragment = FALSE;
ctx->opcode = ctx->opcodeFragment;
}
else
{
if((ctx->opcode == WS_FRAME_OPCODE_CLOSE || ctx->opcode == WS_FRAME_OPCODE_PING || ctx->opcode == WS_FRAME_OPCODE_PONG)
&& ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
{
/* control frame autorisee au milieu de fragment */
ctx->controlInFragment = TRUE;
dynSetLen(e, &ctx->contentControl, 0);
}
else
{
/* opcode incorrect suite fragment suivant */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_FRAGMENT_KO;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
}
}
/* */
ctx->mask = (ctx->frameHeader.ptr[1] & 1);
ctx->len = (ctx->frameHeader.ptr[1] >> 1);
if( ! ctx->mask)
{
/* erreur : le client doit masquer tous ses messages */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_MISSING_MASK;
ctx->controlInFragment = FALSE;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
if( ctx->opcode != WS_FRAME_OPCODE_TEXT && ctx->opcode != WS_FRAME_OPCODE_BINARY &&
ctx->opcode != WS_FRAME_OPCODE_CLOSE && ctx->opcode != WS_FRAME_OPCODE_PING && ctx->opcode != WS_FRAME_OPCODE_PONG)
{
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_OPCODE_KO; /* opcode inconnu/non pris en charge */
ctx->controlInFragment = FALSE;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
if(ctx->len < 126)
ctx->lengthToRead = 4; /* masking key */
else if(ctx->len == 126)
ctx->lengthToRead = 6; /* longueur sur 2 octets a suivre (+ masking key) */
else
ctx->lengthToRead = 12; /* forcement 127 ici => longueur sur 8 octets a suivre (+ masking key) */
/* */
ctx->state = WSSTATE_READINGFRAMEHEADEREXT;
}
}
/* */
if(ctx->state == WSSTATE_READINGFRAMEHEADEREXT)
{
if(data->mLg == 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
/* lecture longueur si sur 2/8 octets + masking key */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->frameHeader, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues, decodage de la frame */
dynConcatSz(e, &ctx->frameHeader, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
/* */
int posMaskey = 2;
if(ctx->len < 126)
ctx->lengthToRead = ctx->len;
else if(ctx->len == 126)
{
ctx->lengthToRead = (ent64s)ctx->frameHeader.ptr[2] + ((ent64s)ctx->frameHeader.ptr[3] << 8);
posMaskey = 4;
}
else
{
ctx->lengthToRead = (ent64s)ctx->frameHeader.ptr[2] + ((ent64s)ctx->frameHeader.ptr[3] << 8) ;
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[4] << 16) + ((ent64s)ctx->frameHeader.ptr[5] << 24);
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[6] << 32) + ((ent64s)ctx->frameHeader.ptr[7] << 40);
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[8] << 48) + ((ent64s)ctx->frameHeader.ptr[9] << 56);
posMaskey = 10;
}
memcpy(ctx->maskey, ctx->frameHeader.ptr + posMaskey, 4);
/* */
ctx->state = WSSTATE_READINGFRAMECONTENT;
}
}
/* */
if(ctx->state == WSSTATE_READINGFRAMECONTENT)
{
if(data->mLg == 0 && ctx->lengthToRead != 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, ctx->controlInFragment ? &ctx->contentControl : &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues */
if(ctx->lengthToRead != 0)
{
dynConcatSz(e, ctx->controlInFragment ? &ctx->contentControl : &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
}
/* appliquer le maskey a chaque octet lu */
if( ! ctx->controlInFragment)
for(long cpt = 0; cpt < ctx->content.mLg; cpt++)
ctx->content.ptr[cpt] ^= ctx->maskey[cpt % 4];
else
for(long cpt = 0; cpt < ctx->contentControl.mLg; cpt++)
ctx->contentControl.ptr[cpt] ^= ctx->maskey[cpt % 4];
/* ping : envoyer pong 0xA1, 0x00, pong ras, close couper la comm' + reset proto websocket */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->lengthToRead = 0;
ctx->controlInFragment = FALSE;
if(ctx->opcode == WS_FRAME_OPCODE_CLOSE)
return WS_REQUEST_CLOSE;
else if(ctx->opcode == WS_FRAME_OPCODE_PING)
return WS_REQUEST_PING;
else if(ctx->opcode == WS_FRAME_OPCODE_PONG)
return WS_REQUEST_PONG;
else
return (ctx->fragment ? WS_REQUEST_FRAGMENT : WS_REQUEST_COMPLETE);
}
}
/* */
ctx->state = WSSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
return WS_REQUEST_ERROR;
}
WAPIDECL long MakeExpectContent(env * e, modCtxWs * ctx, Dynamic * reponse)
{
dynLet(e, reponse, ctx->line.mPtr, ctx->line.mLg); /* handshake http before framing control */
return OK;
}
WAPIDECL long MakeFrame(env * e, modCtxWs * ctx, int frameType, Dynamic * data, Dynamic * response)
{
if(frameType != WS_FRAME_OPCODE_CLOSE && frameType != WS_FRAME_OPCODE_PING && frameType != WS_FRAME_OPCODE_PONG &&
frameType != WS_FRAME_OPCODE_TEXT && frameType != WS_FRAME_OPCODE_BINARY)
return WS_OPCODE_KO;
ent64s lg = 0;
if(data)
if((lg = data->mLg) > 65536ll * 65536ll)
return WS_LENGTH_TOO_HIGH; /* what if length too high : fragment ? refuse ? */
/* */
dynSetLen(e, response, 0);
response->ptr[0] = (frameType << 4) + WS_FRAME_FRAGMENT_OFF;
int posMaskey = 2;
if(lg < 126)
response->ptr[1] = (((octet)lg) << 1) + WS_FRAME_MASK_OFF; // only server mode, and so no masking
else if(lg < 65536)
{
response->ptr[1] = (((octet)126) << 1) + WS_FRAME_MASK_OFF;
response->ptr[2] = (octet)(lg & 255); /* 2 bytes, little endian */
response->ptr[3] = (octet)(lg >> 8);
posMaskey = 4;
}
else
{
response->ptr[1] = (((octet)127) << 1) + WS_FRAME_MASK_OFF;
response->ptr[2] = (octet)(lg & 255); /* 8 bytes, little endian */
response->ptr[3] = (octet)((lg >> 8) & 255);
response->ptr[4] = (octet)((lg >> 16) & 255);
response->ptr[5] = (octet)((lg >> 24) & 255);
response->ptr[6] = (octet)((lg >> 32) & 255);
response->ptr[7] = (octet)((lg >> 40) & 255);
response->ptr[8] = (octet)((lg >> 48) & 255);
response->ptr[9] = (octet)(lg >> 56);
posMaskey = 10;
}
/* for instance, no mask key */
if( ! dynCtrl(e, response, posMaskey + lg, TRUE))
{
dynSetLen(e, response, 0);
return WS_MEMORY;
}
if(lg > 0)
memcopie(response->ptr + posMaskey, data->ptr, lg);
dynSetLen(e, response, posMaskey + lg);
/* */
return OK;
}
+6 -3
View File
@@ -1,4 +1,4 @@
blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,free,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60,format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70,lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80,indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90,multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99
blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102
1,-1,20:09
1,1,3B;0,-1,00-FF
1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E
@@ -43,7 +43,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73
1,1,74;1,1,68;1,1,69;1,1,73
1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74
1,1,66;1,1,72;1,1,65;1,1,65
1,1,68;1,1,6F;1,1,6C;1,1,64
1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E
1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70
1,1,69;1,1,6E;1,1,74
@@ -51,6 +51,8 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,61;1,1,62;1,1,73
1,1,6E;1,1,65;1,1,67
1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64
1,1,73;1,1,71;1,1,72;1,1,74
1,1,65;1,1,78;1,1,70
1,1,74;1,1,79;1,1,70;1,1,65
1,1,6C;1,1,65;1,1,6E
1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74
@@ -58,6 +60,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64
1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78
1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68
1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68
1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65
1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74
1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74
@@ -80,7 +83,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,5B
1,1,5D
1,1,21
1,1,3F
1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66
1,1,22;0,765,20-21:23-EF;1,1,22
1,1,27;0,765,20-26:28-EF;1,1,27
1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39