78 Commits
Author SHA1 Message Date
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
fred ba010944e2 WIP fn mod, shmMod 2025-09-28 17:36:18 +02:00
fred 2b076ebd18 WIP pdfMod + revoir le test des fonctions 2025-09-27 21:20:21 +02:00
fred 7cdd94920e WIP modPdf 2025-09-14 19:46:07 +02:00
fred 764752c3c5 feat: real 0.2 2025-09-13 19:08:41 +02:00
fred 84548796b2 WIP unassemble instruction during tracing 2025-08-31 15:23:31 +02:00
fred eb4a60f1e5 feat: module pdf 2025-08-24 20:03:32 +02:00
fred 523a925d0c feat: maj buffer pour message queue 2025-08-23 18:50:54 +02:00
fred 5967052eef fix: lex rules in program, trace display 2025-08-17 18:41:18 +02:00
fred 592298a3df WIP gestion _bin _binaddr _srcdbg avec library 2025-08-17 15:58:41 +02:00
fred a0cf21e3aa WIP 2025-08-16 20:15:12 +02:00
fred c051bfa423 WIP 2025-08-02 18:53:48 +02:00
fred 150697206a feat: modLzw ok et optimise 2025-07-19 19:06:38 +02:00
fred dde78f169b WIP gestion utf8 + lzw 2025-07-19 16:53:31 +02:00
fred bc4be93744 feat: add feat debug mode + lex files 2025-05-11 18:44:57 +02:00
fred dd6f3ebbcf feat: affichage nom fichier + ligne source en cours + compatibilite Windows 2025-05-11 16:52:19 +02:00
fred 3ae1e8c019 feat: json mod 2025-05-08 15:47:59 +02:00
fred 31acb7939d WIP Windows + test READ.md convert from DokuWiki 2025-05-04 19:02:04 +02:00
90 changed files with 301351 additions and 5736 deletions

No files matched your search

+39 -3
View File
@@ -30,6 +30,9 @@ var pour la shared lib, puis exécution :
```
export LD_LIBRARY_PATH=/home/fde/dev/langage/w/exec
(sur le serveur de dev. pour que ce soit compatible avec la version installee)
sudo ln -s /home/fde/dev/langage/w/lex /etc/wlanguage
exec/lw -t -WBIN:./exec -WSRC:. test
```
@@ -40,10 +43,43 @@ ldd
objdump/readelf (moins bien)
cat /proc/*/maps et faire des grep pour voir les .so et module chargés par opendl
```
# Compilation
# Compilation et execution
```
# exec/lwc $1.w $1.wa < $1.w ; exec/lwa $1.wa ; exec/lw $1
exec/genw $1.w && exec/lwa $1.wa ; exec/lw $1
exec/genw $1.w && exec/lwa $1.wa && rm $1.wa && exec/lw $1
```
# Site Web
https://www.lanisys.fr/wiki/doku.php?id=w
https://w.lanisys.fr/
## LANGAGE W
### Présentation
Le but du langage W est d’être simple, efficace, robuste.
Il est fourni avec un compilateur qui génère un code binaire de type
*p-code*, compatible toute plateforme.
Un exécuteur de p-code W sera disponible sur Linux et d’autres OS.
Un interpréteur W permet également d’exécuter un programme W en mode
*script*.
Un module FastCGI permettra de plus d’utiliser le langage W en mode
interprété ou compilé pour les sites Internet.
Enfin, les programmes W pourront être appelés depuis d’autres
programmes, un peu comme un langage de plugins.
Deux utilitaires permettent de formatter le code source et de générer de
la documentation à partir de *tags* dans le code, au format
[DokuWiki](https://www.dokuwiki.org/dokuwiki).
Description du fonctionnement des [programmes](/w/prog) d’exécution et
compilation.
Pour démarrer, premier programme d’exemple :
``` w
; Le celebre Hello world en W
begin hello
echonl "Hello world !"
except
end
```
Voici la description complète du [langage W](/w/instr).
+34
View File
@@ -0,0 +1,34 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#undef WAPIDECL
#define WAPIDECL
// for windows compilation and generating/using import library
#ifdef WAPIEXPORT
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#endif
#ifdef WAPIIMPORT
#undef WAPIDECL
#define WAPIDECL __declspec(dllimport)
#endif
+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
*/
}
+286 -291
View File
File diff suppressed because it is too large. Load diff
+237
View File
@@ -0,0 +1,237 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "langage.h"
#include "var.h"
#include "buffer.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/*
Dans le contexte des IPC, memoire partagee, contenant un buffer (donc partagé), le champ "ptr" pointe forcement a la suite de l'entete,
car un malloc ne fonctionne pas en inter process.
Contrairement à la création avec "var_init", destiné a ne pas etre partage, ptr est créé par un malloc
La macro BUFPTR permet de gerer ces 2 cas : si le buffer est en memoire partagee, le champ ptr = NULL et il suffit alors d'aller juste apres l'entete
pour trouver les donnees. Si le buffer est cree avec var_init, il faut utiliser la valeur de ptr directement.
*/
/*
lgmax = taille buffer
max lg message = lgmax - 4 => un message = lg (2 octets) + msg
cas 0 read = write : buffer vide : lg msg max = lgmax - 4 (et maxi 65535)
cas 1 : read <= write (inclus cas 0)
+-------------^*********************^------------------+ lgmax
read write
occ = write - read ; free = lgmax - (write - read) - 4
cas 2 : read > write
+********^---------------------------------------^*****+ lgmax
write read
occ = write + (lgmax - read) ; free = read - write - 4
*/
//#define BUFPTR(x) (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr)
pointeur BUFPTR(var * x)
{
return (pointeur)(x->ptr == NULL ? (pointeur)(x + sizeof(var)) : x->ptr);
}
WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
{
ent16 lg, lgfin; /* taille max d'un element dans un buffer : 64 Ko */
ent64 p;
if(varbuf == NULL || v == NULL)
return;
if(varbuf->type != VAR_BUFFER)
return;
/* */
if(v->type == VAR_PARAM)
{
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);
var_init(e, v, VAR_DYNAMIC, 0, 0, NULL);
if(v->type == VAR_NULL)
{
/* erreur alloc memoire */
e->exception = EX_MEM;
return;
}
}
dynLet(e, v, NULL, DYN_LGNONE);
if(varbuf->read == varbuf->write)
return; /* buffer vide : var dynamic vide aussi */
/* */
p = varbuf->read;
lg = *(octet *)(BUFPTR(varbuf) + p++) * 256;
if(p >= varbuf->lgmax) p = 0;
lg += *(octet *)(BUFPTR(varbuf) + p++);
if(p >= varbuf->lgmax) p = 0;
if(lg > 0)
{
if(dynCtrl(e, v, lg, TRUE) != DYN_OK) /* avec RAZ */
return;
/* */
if(lg <= (lgfin = varbuf->lgmax - p))
{
/* copier un seul bloc */
memcopie(v->ptr, BUFPTR(varbuf) + p, lg);
v->lg = lg;
*(v->ptr + lg) = 0; /* \0 de fin de chaine */
if(p + lg >= varbuf->lgmax)
varbuf->read = 0; /* cela ne peut pas etre plus loin, car sinon il y aurait eu 2 blocs a lire */
else
varbuf->read = p + lg;
}
else
{
/* 2 blocs */
memcopie(v->ptr, BUFPTR(varbuf) + p, lgfin);
memcopie(v->ptr + lgfin, BUFPTR(varbuf), lg - lgfin);
varbuf->read = lg - lgfin;
}
}
else
varbuf->read = p;
}
WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
{
ent64 p, lgfin;
if(varbuf == NULL || v == NULL)
return;
if(v->type == VAR_PARAM)
{
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;
if(v->lg > (varbuf->lgmax / 2)) // pour pouvoir ecrire au moins 2 items dans le buffer
{
e->exception = EX_BUFOVF; /* trop grand a ecrire */
return;
}
ent64 vbread = varbuf->read;
if(varbuf->write < vbread)
{
/* ecriture en une fois, + 3 car lg sur 16 bits en plus et laisser au moins 1 octet libre => read=write veut dire vide ! */
if(vbread - varbuf->write < v->lg + 3)
{
e->exception = EX_BUFOVF; /* pas assez de place */
return;
}
/* */
p = varbuf->write;
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
p++;
*(BUFPTR(varbuf) + p) = v->lg & 255;
p++;
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
varbuf->write = p + v->lg;
}
else
{
/* ecriture en une ou 2 fois */
if(varbuf->lgmax + vbread - varbuf->write < v->lg + 3) /* lgbuffer - (write - read) */
{
e->exception = EX_BUFOVF; /* pas assez de place */
return;
}
p = varbuf->write;
*(BUFPTR(varbuf) + p) = (v->lg & 65535) >> 8;
p++;
if(p >= varbuf->lgmax) p = 0;
*(BUFPTR(varbuf) + p) = v->lg & 255;
p++;
if(p >= varbuf->lgmax) p = 0;
if(v->lg == 0)
{
varbuf->write = p;
return;
}
if(v->lg <= (lgfin = varbuf->lgmax - p))
{
/* copier en une fois */
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
if(p + v->lg >= varbuf->lgmax)
varbuf->write = 0; /* pas plus cas sinon il y aurait eu copie en 2 fois */
else
varbuf->write = p + v->lg;
}
else
{
/* en 2 fois */
memcopie(BUFPTR(varbuf) + p, v->ptr, lgfin);
memcopie(BUFPTR(varbuf), v->ptr + lgfin, v->lg - lgfin);
varbuf->write = v->lg - lgfin;
}
}
}
WAPIDECL void buffer_clear(env * e, var * varbuf)
{
if(varbuf == NULL)
return;
if(varbuf->type != VAR_BUFFER)
return;
varbuf->read = 0;
varbuf->write = 0;
memset(BUFPTR(varbuf), 0, varbuf->lgmax);
}
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg)
{
if(varbuf == NULL)
return;
if(varbuf->type != VAR_BUFFER)
return;
printf("buffer lgmax=%lld read=%lld write=%lld\n", varbuf->lgmax, varbuf->read, varbuf->write);
if(lg == 0)
lg = varbuf->lgmax;
/* affichage brut en hexa */
hex2((char *)BUFPTR(varbuf), lg, 32);
}
+35
View File
@@ -0,0 +1,35 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifndef BUFFER_H
#define BUFFER_H
#include "apidecl.h"
WAPIDECL void buffer_read(env * e, var * varbuf, var * v);
WAPIDECL void buffer_write(env * e, var * varbuf, var * v);
WAPIDECL void buffer_clear(env * e, var * varbuf);
WAPIDECL void buffer_printdebug(env * e, var * varbuf, ent32 lg);
/* ********************************************** */
#endif
+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);
+167
View File
@@ -0,0 +1,167 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "cipher.h"
typedef struct {
int error; // dernier code erreur specifique au module
modContextCipher ctxMod;
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
/* *********************************************************************************** */
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// les differentes fonctions (en plus des 4 obligatoires) :
// MD2(entree, resultat)
// MD4(entree, resultat)
//
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 */
//
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
/* ----------------------------------------------------------------------------------------------- */
/* 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
cipherInit(e, &p_etat->ctxMod);
}
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
cipherEnd(e, &p_etat->ctxMod);
//printf("mod end %d\n", p_etat->test);
memfree(e, p_etat);
}
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODETAT;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
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_MODETAT;
else if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toAES128", 8))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
setError(p_etat, cipher_AES128(e, &p_etat->ctxMod, param1, param2, param3)); /* param1 = key, param2 = input, param3 = output */
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromAES128", 10))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
setError(p_etat, decipher_AES128(e, &p_etat->ctxMod, param1, param2, param3)); /* param1 = key, param2 = input, param3 = output */
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
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;
}
+62 -19
View File
@@ -1,36 +1,67 @@
BUILD=`date +%Y%m%d%H%M%S`
echo BUILD $BUILD
echo 0. Compilation pour shared lib
gcc -c w_src/dynamic.c -s -Wall -DUNIX -m64 -fPIC -o exec/dynamic.o
gcc -c w_src/dynamic.c -s -Wall -DUNIX -m64 -fPIC -o exec/dynamic.o -Wno-unused-value
gcc -c w_src/var.c -s -Wall -DUNIX -m64 -fPIC -o exec/var.o
gcc -c w_src/hashtable.c -s -Wall -DUNIX -m64 -fPIC -o exec/hashtable.o
gcc -c w_src/buffer.c -s -Wall -DUNIX -m64 -fPIC -o exec/buffer.o
gcc -c w_src/global.c -s -Wall -DUNIX -m64 -fPIC -o exec/global.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o -o exec/libw.so
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o
gcc -c w_src/rep.c -s -Wall -DUNIX -m64 -fPIC -o exec/rep.o
gcc -c w_src/lex.c -s -Wall -DUNIX -m64 -fPIC -o exec/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 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.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/lzw_lib.so w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/lzw.o w_src/lzwMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:lzw_lib.so
echo 5. Compilation de pdfMod.c
gcc -shared -s -o exec/pdf_lib.so w_src/pdf_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/pdf.o w_src/pdfMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:pdf_lib.so -l:lzw_lib.so
echo 6. Compilation de jsonMod.c
gcc -shared -s -o exec/json_lib.o w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.o
gcc -shared -s -o exec/json_lib.so w_src/json_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/json.o w_src/jsonMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:json_lib.so
echo 6. Compilation de shmMod.c
gcc -shared -s -o exec/shm_lib.so w_src/shm_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/shm.o w_src/shmMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:shm_lib.so
echo 7. Compilation de timeMod.c
gcc -shared -s -o exec/time.o w_src/timeMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
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
@@ -38,21 +69,33 @@ 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
echo 14. Generation du generateur de fichier lex
gcc w_src/genlex.c -o exec/genlex -s -Wall -m64 -DUNIX -L./exec -l:libw.so
gcc w_src/genlex.c -o exec/wlex -s -Wall -m64 -DUNIX -L./exec -l:libw.so
echo 15. Generation de l\'analyseur de source w
gcc w_src/genw.c -s -o exec/genw -Wall -m64 -DUNIX -Wno-stringop-truncation -L./exec -l:libw.so
echo 15. Generation de l\'analyseur de source w \(compilateur w\)
gcc w_src/genw.c -s -o exec/lwc -Wall -m64 -DUNIX -Wno-stringop-truncation -L./exec -l:libw.so
echo "compress => gcc compress.c -s -o compress -Wall -m64 -DUNIX -L./exec -l:libw.so"
echo "test_utf => gcc test_utf.c -s -o utf -Wall -m64 -DUNIX -L./exec -l:libw.so -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 "rep => gcc rep.c -s -o rep -Wall -m64 -DUNIX -L./exec -l:libw.so"
echo "package => dpkg-deb --build wlanguage"
+105
View File
@@ -0,0 +1,105 @@
@echo off
cd "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build"
call vcvars64.bat
cd "C:\Users\Poupougne42\source\repos\win_w_src"
echo ------------------------------------------------------------------------------------------
echo 0. Compilation pour dynamic lib DLL
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\libw.dll w_src\dynamic.c w_src\var.c w_src\hashtable.c w_src\buffer.c w_src\global.c w_src\rep.c w_src\lex.c 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
echo 1b. Compilation de fileMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\file.dll w_src\fileMod.c exec\libw.lib /DEBUG:NONE
echo 1c. Compilation de timeMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\time.dll w_src\timeMod.c exec\libw.lib /DEBUG:NONE
echo 1d. Compilation de hashMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\hash_lib.dll w_src\hash_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\hash.dll w_src\hashMod.c exec\libw.lib exec\hash_lib.lib /DEBUG:NONE
echo 1e. Compilation de systemMod.c (ws2_32.lib pour socket)
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\system.dll w_src\systemMod.c exec\libw.lib ws2_32.lib advapi32.lib /DEBUG:NONE
echo 1f. Compilation de randomMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\random.dll w_src\randomMod.c exec\libw.lib /DEBUG:NONE
echo 1g. Compilation de cipherMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\cipher_lib.dll w_src\cipher_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\cipher.dll w_src\cipherMod.c exec\libw.lib exec\cipher_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 2a. Compilation de jsonMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\json_lib.dll w_src\json_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /DEBUG:NONE
echo 2b. Compilation de shmMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\shm_lib.dll w_src\shm_lib.c exec\libw.lib advapi32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\shm.dll w_src\shmMod.c exec\libw.lib exec\shm_lib.lib /DEBUG:NONE
echo 2c. Compilation de lzwMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\lzw_lib.dll w_src\lzw_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lzw.dll w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
echo 2d. Compilation de pdfMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\pdf_lib.dll w_src\pdf_lib.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\pdf.dll w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib /DEBUG:NONE
echo 2e. Compilation de sockMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sock_lib.dll w_src\sock_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\sock.dll w_src\sockMod.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE
echo 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 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
+189
View File
@@ -0,0 +1,189 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "convert.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_CONVFMT 1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
//
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(modFnIs(e, "toHexa", 6))
{
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(str2hex(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromHexa", 8))
{
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(hex2str(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "toBase64", 8))
{
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(str2base64(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "fromBase64", 10))
{
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(base642str(e, param1, param2) != DYN_OK)
exc = EXMOD_CONVFMT;
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
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
+634 -211
View File
File diff suppressed because it is too large. Load diff
+11
View File
@@ -0,0 +1,11 @@
; liste des commandes et mots cles en mode debug
blanc: (1,*,#20#09#0A#0D)
commande: (1,2,a-zA-Z)
aide: (1,1,?)
nombre: (1,9,0-9)
ajouter: (1,1,#2B) ; +
supprimer:(1,1,#2D) ; -
ident: (1,1,#3A) (1,1,a-zA-Z_) (0,23,a-zA-Z0-9) ; :_abcABC123
identnext:(1,1,#2E) (1,1,a-zA-Z) (0,23,a-zA-Z0-9) ; .abcABC123
reste: (1,1,#00-#FF)
+99
View File
@@ -0,0 +1,99 @@
;
; for background w process debugging
; using shm_lib on buffer "dbg<pid>" for the debugged process
; Usage: lw debug <pid2debug>
;
begin wdebug
declare idProc, msg, pid, cmd, ret, capt, again, delay, debugging, signal
declare OK, ERROR
let debugging = @false
let OK = 0
let ERROR = neg(1)
;
sub WriteProcess(id, message, cr)
invoke shm&set(id, message)
let cr = OK
except
let cr = ERROR
catch
endsub
;
sub ReadProcess(message, cr)
invoke shm&get(message)
let cr = OK
except
let cr = ERROR
catch
endsub
; ********************************************************
;
let pid = field(@arg, @currfm, 2)
if pid = '' or type(pid) # @varnumber then
let msg = 'Incorrect pid number (':pid:'), abort'
echonl msg
return
endif
;
let idProc = 'dbg':pid
let msg = 'Start debugging process ':pid
echonl msg
;
loop
let msg = 'Sending SIGUSR1 signal and wait 1 second'
echonl msg
let capt = ''
let ret = 0
let signal = 10
invoke system&sendSignal(pid, signal)
; now waiting for shm to init from signaled process
let delay = 1
invoke system&sleep(delay)
;
let msg = '%':@prog
do WriteProcess(idProc, msg, ret)
breakon ret = OK
; retry ?
let msg = 'Process ':pid:" don't respond to debug start message (":msg:"), try again (Y/N) ? "
echo msg
input again
breakon again # 'y' and again # 'Y'
endloop
returnon ret # OK
;
; ok, we can debug background process now
; 1. read prompt
; 2. get command from user
; 3. send command
; 4. repeat from step 1
let msg = "Ready for debuging... ('q' to end session)"
echonl msg
let delay = 0.1
let debugging = @true
loop
do ReadProcess(msg, ret)
breakon ret # OK or msg = '%'
if msg # '' then
echo msg
loop
let cmd = ''
input cmd
breakon cmd # ''
endloop
;
do WriteProcess(idProc, cmd, ret)
breakon ret # OK
else
invoke system&sleep(delay)
endif
endloop
let msg = "End of debugging"
echonl msg
;
except
if debugging then
let cmd = '%'
do WriteProcess(idProc, cmd, ret)
endif
let msg = 'Exception ':@except
echonl msg
end
+9
View File
@@ -0,0 +1,9 @@
blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,reste,8
1,-1,20:09:0A:0D
1,2,61-7A:41-5A
1,1,3F
1,9,30-39
1,1,2B
1,1,2D
1,1,3A;1,1,5F:61-7A:41-5A;0,23,61-7A:41-5A:30-39
1,1,00-FF
+1179 -896
View File
File diff suppressed because it is too large. Load diff
+104 -78
View File
@@ -23,109 +23,135 @@
#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
#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
{
long mLg, mLgmax, mInternal;
char * mPtr;
short codePage;
} Dynamic;*/
typedef var Dynamic;
#define DYN_LGMIN 256
/*
pour la gestion de l'UTF8, revoir les methodes suivantes :
getLen, count, substr, erase, convert, cut
pour la gestion de l'UTF8, revoir les methodes suivantes (https://en.wikipedia.org/wiki/UTF-8) :
getLen, count, substr [x,y], erase, convert, cut
(+ version de getLen sur une chaine sz ; getLen doit remplacer l'utilisation de mLg dans certains cas / creer un getCharLen)
travailler en lg physique dans dynamic.c (c'est le cas) et si utf-8, faire un "pre-traitement" pour retrouver la lg physique
à partir de la lg "logique" quand besoin ; si pas possible, evo dans chaque methode de dynamic.c ou plutot faire une 2eme methode pour l'UTF8 !!
si erreur de codage/lecture utf8, la norme est de le remplacer par le point de code \uFFFD (EF BF BD) et de continuer (à convertir en 3F ? par exemple en mono byte)
*/
#include "apidecl.h"
/* ********************************************** */
void NumberToSz(env * e, ent64s valeur, char * resultat, long * lg);
char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
char * Int32ToSz(ent32s valeur, long signe, long leftPad);
long dynInit(env * e, Dynamic * this, long lgmax);
long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
void dynFree(env * e, Dynamic * this);
void dynSetLen(env * e, Dynamic * this, long lg);
long dynLgU8(env * e, Dynamic * this);
long dynCtrl(env * e, Dynamic * this, long lg, long copier);
void Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
void UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
long dynSetAsSz(env * e, Dynamic * this, char * chaine);
long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
long dynRead(env * e, Dynamic * this, char * fichier);
long dynWrite(env * e, Dynamic * this, char * fichier);
ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
ent64s dynToNumber(env * e, Dynamic * this);
long dynConvertError(env * e, Dynamic * this);
long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
void dynBegin(env * e, Dynamic * this);
long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
long dynConvert(env * e, Dynamic * this, char * from, char * to);
void dynReplace(env * e, Dynamic * this, char from, char to);
void dynErase(env * e, Dynamic * this, char * car);
long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
long dynConvertHexaToLong(Dynamic * valeur);
long dynConvertCharHexaToChar(char c1, char c2, char * c);
long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg);
long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadrage, char filler, long lg);
long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option);
WAPIDECL char * NumberToSz(env * e, ent64s valeur, char * resultat, ent64s * lg);
WAPIDECL char * Int64ToSz(env * e, ent64s valeur, long signe, long leftPad);
WAPIDECL char * Int32ToSz(ent32s valeur, long signe, long leftPad);
WAPIDECL long dynInit(env * e, Dynamic * this, long lgmax);
WAPIDECL long dynCopy(env * e, Dynamic * this, Dynamic * aCopier);
WAPIDECL void dynFree(env * e, Dynamic * this);
WAPIDECL void dynSetLen(env * e, Dynamic * this, long lg);
//long dynCarU8(env * e, Dynamic * this, long * pos);
//long dynLgU8(env * e, Dynamic * this);
WAPIDECL long dynLengthUtf8(const char * p, long lg, int separator);
WAPIDECL long dynNextUtf8(char ** p, long lg, long * pos, char * carU8, int separator);
WAPIDECL long dynCtrl(env * e, Dynamic * this, long lg, long copier);
WAPIDECL long Win1252ToUTF8(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL long UTF8ToWin1252(env * e, Dynamic * valeur, Dynamic * resultat);
WAPIDECL void NumberToBin(env * e, ent64s valeur, pointeur resultat, int nbOctet, int signe, int endianess);
WAPIDECL void BinToNumber(env * e, pointeur valeur, ent64s * resultat, int nbOctet, int signe, int endianess);
WAPIDECL long dynSetAsNumber(env * e, Dynamic * this, ent64s valeur);
WAPIDECL long dynSetAs(env * e, Dynamic * this, Dynamic * valeur);
WAPIDECL long dynSetAsSz(env * e, Dynamic * this, char * chaine);
WAPIDECL long dynLet(env * e, Dynamic * this, char * chaine, long lgChaine);
WAPIDECL long dynCompare(env * e, Dynamic * this, ent64 comparaison, char * chaine, long lgChaine);
WAPIDECL long dynRead(env * e, Dynamic * this, char * fichier);
WAPIDECL long dynWrite(env * e, Dynamic * this, char * fichier);
WAPIDECL ent64s dynSzToNum(env * e, char * chaine, long signe, long nbLuMax, long * error);
WAPIDECL ent64s dynToNum(env * e, Dynamic * this, long signe, long nbLuMax);
WAPIDECL ent64s dynToNumber(env * e, Dynamic * this);
WAPIDECL long dynConvertError(env * e, Dynamic * this);
WAPIDECL long dynConcatSz(env * e, Dynamic * this, char * chaine, long lgChaine);
WAPIDECL long dynConcat(env * e, Dynamic * this, Dynamic * valeur);
WAPIDECL long dynConcatNumber(env * e, Dynamic * this, ent64s valeur);
WAPIDECL long dynStoreSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynStore(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynStoreNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynField(env * e, Dynamic * this, Dynamic * resultat, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
WAPIDECL ent64s dynFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynExtractField(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
WAPIDECL long dynExtractSubField(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
WAPIDECL ent64s dynExtractFieldAsNumber(env * e, Dynamic * this, long numChamp, Dynamic * resultat);
WAPIDECL ent64s dynExtractSubFieldAsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * resultat);
WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp, char * chaine, long lgChaine, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynIns(env * e, Dynamic * this, long numChamp, long numSousChamp, Dynamic * valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynInsNumber(env * e, Dynamic * this, long numChamp, long numSousChamp, ent64s valeur, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynDel(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp, long nb);
WAPIDECL long dynLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long numChamp, char separateurChamp);
WAPIDECL long dynSortLocateSz(env * e, Dynamic * this, char * chaine, char separateur, long tri, long numChamp, char separateurChamp);
WAPIDECL long dynDcount(env * e, Dynamic * this, char caractere, long numChamp, char separateurChamp);
WAPIDECL void dynBegin(env * e, Dynamic * this);
WAPIDECL long dynNext(env * e, Dynamic * this, Dynamic * resultat, char separateur);
WAPIDECL long dynRemove(env * e, Dynamic * this, Dynamic * resultat, char separateur, long raz);
WAPIDECL long dynExtractPos(env * e, Dynamic * this, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynCount(env * e, Dynamic * this, char caractere, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynCountUtf8(env * e, Dynamic * this, char * caractere4, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSetSubstr(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSetSubstrUtf8(env * e, Dynamic * this, Dynamic * valeur, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSubstr(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL long dynSubstrUtf8(env * e, Dynamic * this, Dynamic * resultat, long debut, long len, long numChamp, long numSousChamp, char separateurChamp, char separateurSousChamp);
WAPIDECL char ** dynToTabPtr(env * e, Dynamic * this, char separateur);
WAPIDECL long dynConvert(env * e, Dynamic * this, char * from, char * to);
WAPIDECL void dynReplace(env * e, Dynamic * this, char from, char to);
WAPIDECL long dynConvertUtf8(env * e, Dynamic * this, char * from, char * to);
WAPIDECL void dynErase(env * e, Dynamic * this, char * car);
WAPIDECL void dynEraseUtf8(env * e, Dynamic * this, char * car);
WAPIDECL long dynIndexSz(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
WAPIDECL long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
WAPIDECL long dynIndexSzUtf8(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
WAPIDECL long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long 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"
*/
+154 -92
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -26,10 +26,10 @@
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/types.h>
#else
#include "windows.h" // pour les fonctions FindFile...
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
@@ -42,7 +42,11 @@ typedef struct {
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
#define EXMOD_RENAME 1
#define EXMOD_REMOVE 2
#define EXMOD_READ 3
#define EXMOD_WRITE 4
#define EXMOD_ACCESS 5 /* open seek */
static int setError(modEtat * p, int err)
{
@@ -51,13 +55,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -74,17 +77,24 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
// set : ecrit depuis param le dynamic dans le fichier (param = nom FM contenu)
// size : donne la taille sur disque du fichier
// dir : donne la liste des fichiers et repertoires d'un repertoire
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
//printf("In fileMod (dlfcn) : fonction %s(%s)\n", e->fn, param->mPtr);
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -97,141 +107,193 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
//*** code specifique ici
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
//printf("mod end %d\n", p_etat->test);
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); // version 1 ici
else if(param->type == VAR_NUMBER)
param->num = NUM_UN;
if(param1 == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "create", 6) == 0)
else if(modFnIs(e, "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 */
if(param->type == VAR_DYNAMIC)
{
if(dynRead(e, param, param->mPtr) != DYN_OK)
exc = setError(p_etat, 1);
}
else
exc = EX_MODPARAM; /* TODO code */
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "set", 3) == 0)
{
/* copie du code de dynWrite, avec modif car c'est la meme var dyn qui contient nom + contenu */
FILE * fic;
ent64s lg;
/* */
dynRemove(e, param, 0, 0, TRUE);
if(dynRemove(e, param, &e->int_dynamic, cFM, FALSE) < 0)
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
lg = e->int_dynamic.mInternal + 1;
#ifndef UNIX
if((fic = fopen(e->int_dynamic.mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(e->int_dynamic.mPtr, "w")) == NULL)
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fwrite(param->mPtr + lg, param->mLg - lg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
fclose(fic);
}
if(rename(param1->mPtr, param2->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "size", 4) == 0)
else if(modFnIs(e, "delete", 6))
{
if(param1 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(remove(param1->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "append", 6))
{
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FILE * fic;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "ab")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "a")) == NULL) /* mode "a" creer le fichier s'il n'existe pas (Unix et Windows) */
#endif
exc = setError(p_etat, EXMOD_ACCESS);
else
{
if(fseek(fic, 0, SEEK_END) != 0)
exc = setError(p_etat, EXMOD_ACCESS);
else if(fwrite(param2->mPtr, param2->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, EXMOD_WRITE);
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* utilisation de dynRead qui fait le travail, param1 : nom, param2 : contenu lu */
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynRead(e, param2, param1->mPtr) != DYN_OK)
exc = setError(p_etat, EXMOD_READ);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* copie du code de dynWrite, avec modif param1 : nom, param2 : contenu a ecrire */
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
FILE * fic;
#ifndef UNIX
if((fic = fopen(param1->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param1->mPtr, "w")) == NULL)
#endif
exc = setError(p_etat, EXMOD_ACCESS); /* erreur generique : lire la vraie erreur ailleurs */
else
{
if(fwrite(param2->mPtr, param2->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, EXMOD_WRITE); /* erreur generique : lire la vraie erreur ailleurs */
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "size", 4))
{
/* copie du code de dynRead, plus court */
FILE * fic;
ent64s lg;
/* */
if(param->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
#ifndef UNIX
if((fic = fopen(param->mPtr, "wb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
if((fic = fopen(param1->mPtr, "rb")) == NULL) /* mode binaire sous Windows, sinon conversions faites en auto ! */
#else
if((fic = fopen(param->mPtr, "w")) == NULL)
if((fic = fopen(param1->mPtr, "r")) == NULL)
#endif
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
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
{
lg = ftell(fic); /* longueur du fichier */
NumberToSz(e, lg, param->mPtr, (long *)&param->mLg); // TODO a verifier
param2->num = lg * NUM_FACTEUR;
}
fclose(fic);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "dir", 3) == 0)
else if(modFnIs(e, "dir", 3))
{
/* copie du code de dynRead, plus court */
/* */
if(param->type != VAR_DYNAMIC)
if(param1 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef UNIX
DIR * rep = NULL;
if((rep = opendir(param->mPtr)) == NULL)
exc = setError(p_etat, 1); /* todo vraie erreur */
if((rep = opendir(param1->mPtr)) == NULL)
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
else
{
dynSetLen(e, param, 0); // idem raz
dynSetLen(e, param1, 0); // idem raz
struct dirent * fic = NULL;
while ((fic = readdir(rep)) != NULL)
{
if((fic->d_type == DT_DIR || fic->d_type == DT_REG) && strcmp(fic->d_name,".") != 0 && strcmp(fic->d_name,"..") != 0)
{
if(param->mLg > 0)
dynConcatSz(e, param, sFM, 1);
dynConcatSz(e, param, fic->d_name, DYN_LGNONE);
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, fic->d_name, DYN_LGNONE);
}
}
/* */
@@ -240,24 +302,24 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
#else
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
dynConcatSz(e, param, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(param->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
dynConcatSz(e, param1, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(param1->mPtr, &FindFileData)) != INVALID_HANDLE_VALUE)
{
dynSetLen(e, param, 0); // idem raz
dynSetLen(e, param1, 0); // idem raz
for(int cr = -1;cr != 0;)
{
if(strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
{
if(param->mLg > 0)
dynConcatSz(e, param, sFM, 1);
dynConcatSz(e, param, FindFileData.cFileName, DYN_LGNONE);
if(param1->mLg > 0)
dynConcatSz(e, param1, sFM, 1);
dynConcatSz(e, param1, FindFileData.cFileName, DYN_LGNONE);
}
cr = FindNextFile(hFind, &FindFileData);
}
FindClose(hFind);
}
else
exc = setError(p_etat, 1); /* todo vraie erreur */
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
#endif
}
}
+42 -15
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,7 +27,7 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
env e;
@@ -49,7 +49,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20
return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30
continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40
new,41,class,42,this,43,parent,44,free,45,precision,46,setsep,47,int,48,frac,49,abs,50
new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50
neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60
format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70
lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80
@@ -61,7 +61,7 @@ struct {
ent16 sub,endsub,if_,then,else_,elseif,endif,do_,call,invoke;
ent16 return_,returnon,loop,endloop,foreach,in,like,endfor,break_,breakon;
ent16 continue_,continueon,nop,part,echonl,echo,input,declare,let,delet;
ent16 new,class,this,parent,free,precision,setsep,int_,frac,abs;
ent16 new,class,this,parent,hold,precision,setsep,int_,frac,abs;
ent16 neg,round,type,len,count,dcount,field,index,search,change;
ent16 format,insert,remove,tonum,tostring,equal,diff,gt,lt,gte;
ent16 lte,and,or,not,beginpar,endpar,beginh,endh,begins,ends;
@@ -119,7 +119,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.class = rg(e, regles, "class", tmp);
r.this = rg(e, regles, "this", tmp);
r.parent = rg(e, regles, "parent", tmp);
r.free = rg(e, regles, "free", tmp);
r.hold = rg(e, regles, "hold", tmp);
r.precision = rg(e, regles, "precision", tmp);
r.setsep = rg(e, regles, "setsep", tmp);
r.int_ = rg(e, regles, "int", tmp);
@@ -181,17 +181,32 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.other = rg(e, regles, "other", tmp);
}
enum {
TAB_COUNT = 3,
COMMENT_EOL = 8
};
static void formatage_asm(Dynamic * s, Dynamic * f)
{
// TODO
}
static void formatage(Dynamic * s, Dynamic * f, int type)
{
// s : source ; f : source apres formatage, type : 1 w, 2 pcode
if(type == 2)
{
formatage_asm(s, f);
return;
}
//Dynamic token; /* contient les tokens suite au decodage lex d'une ligne */
ent16 tok; //,tok2,tok3; /* token lu par la macro ci-dessous "nreg" */
long n; /* indice en cours dans les token (parametre de la macro "nreg") base 1 */
//#define nreg(x) ((x)*2 > token.mLg ? 0 : *(ent16 *)(token.mPtr + (x)*2 - 2))
#define ntok(x) dynExtractSubFieldAsNumber(&e, &valex, 2, x, &tmp)
//
#define TAB_COUNT 3
#define COMMENT_EOL 8
//#define TAB_COUNT 3
//#define COMMENT_EOL 8
//
Dynamic trav, tmp, lig; /* variables de travail */
Dynamic regles; /* regles lex */
@@ -199,7 +214,8 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
//
dynInit(&e, &regles, 0);
//
if(lire_regles_lex(&e, &regles, "/etc/wlanguage/wlex") != DYN_OK) // au lieu de lex/wlex
//if(lire_regles_lex(&e, &regles, "/etc/wlanguage/wlex") != DYN_OK) // au lieu de lex/wlex
if(lire_regles_lex(&e, &regles, "wlex") != DYN_OK)
{
dynLet(&e, f, s->mPtr, s->mLg);
dynFree(&e, &regles);
@@ -235,7 +251,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()
@@ -313,14 +329,25 @@ static void formatage(Dynamic * s, Dynamic * f, int type)
//if(tok2 != r.comment)
// pos_comment = -1;
}
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 10 (par exemple), >= position actuelle
// si pos_comment > -1 traiter le commentaire en fin de ligne, position multiple de 8, >= position actuelle
// + formatage debut de ligne
if(pos_comment == -1)
dynSubstr(&e, &trav, &lig, pos - 1, (long)trav.mPtr - pos, 1, DYN_NONE, 10, DYN_NONE);
{
#ifdef WINLIB
dynSubstr(&e, &trav, &lig, pos - 1, ((intptr_t)(trav.mPtr)) - pos, 1, DYN_NONE, 10, DYN_NONE);
#else
dynSubstr(&e, &trav, &lig, pos - 1, (long)(trav.mPtr - pos), 1, DYN_NONE, 10, DYN_NONE);
#endif
}
else
{
dynSubstr(&e, &trav, &lig, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
dynSubstr(&e, &trav, &tmp, pos_comment - 1, (long)trav.mPtr - pos_comment, 1, DYN_NONE, 10, DYN_NONE);
dynSubstr(&e, &trav, &tmp, pos - 1, pos_comment - pos, 1, DYN_NONE, 10, DYN_NONE);
dynTrim(&e, &tmp, &lig, ' ', 2);
#ifdef WINLIB
dynSubstr(&e, &trav, &tmp, pos_comment - 1, ((intptr_t)(trav.mPtr)) - pos_comment, 1, DYN_NONE, 10, DYN_NONE);
#else
dynSubstr(&e, &trav, &tmp, pos_comment - 1, (long)(trav.mPtr - pos_comment), 1, DYN_NONE, 10, DYN_NONE);
#endif
}
//
if(flag_trt == 1)
@@ -382,7 +409,7 @@ int main(int argc, char * argv[])
type = 1; // par defaut formatage du source w
else if(argc != 3)
{
printf("Usage: wlf [-w|-wa] <source>\n");
printf("Usage: lwf [-w|-wa] <source>\n");
exit(-1);
}
else
@@ -394,7 +421,7 @@ int main(int argc, char * argv[])
type = 2; // formatage du pcode (fichier .wa) TODO
else
{
printf("Usage: wlf [-w|-wa] <source>\n");
printf("Usage: lwf [-w|-wa] <source>\n");
exit(-1);
}
}
+217
View File
@@ -0,0 +1,217 @@
begin gened
;
class Gened = {Base}
;
let Gened.trace = @false
;
let Gened.name = ''
let Gened.query = ''
;
let Gened.breakInfo = ''
let Gened.breakCount = 0
;
let Gened.recordCount = 0
let Gened.init = @true
let Gened.first = @true
let Gened.last = @false
let Gened.currentRecord = ''
let Gened.precRecord = ''
;
; breakInfo, champs en multi-valeurs :
let Gened.BREAKFIELDNUM = 1 ; {1} = num champ dans l'enregistrement
let Gened.BREAKFIELDVAL = 2 ; {2} = valeur champ enreg en cours
let Gened.BREAKFIELDVALPREC = 3 ; {2} = valeur champ enreg en cours
let Gened.BREAKDIFF = 4 ; {4} = flag si difference pour ce niveau
let Gened.BREAKCOUNTER = 5 ; {5} = compteur d'enregs pour ce niveau de rupture
;
sub Gened.ParamSection()
; maj de name/query/breakInfo{1}
if this.trace then
echonl "ED => in ParamSection"
endif
except
endsub
;
sub Gened.SetQuery()
; creer la requete de recuperation des enregistrements (utilise query)
if this.trace then
echonl "ED => in SetQuery"
endif
except
endsub
;
sub Gened.GetNextRecord()
; recupere l'enregistrement suivant, et l'ecrit dans this.currentRecord et this.last = @false, sinon this.last = @true et this.currentRecord = ''
if this.trace then
echonl "ED => in GetNextRecord"
endif
except
endsub
;
sub Gened.EndOfQuery()
; terminer la requete de recup. des enregistrements
if this.trace then
echonl "ED => in EndOfQuery"
endif
except
endsub
;
sub Gened.InitSection()
if this.trace then
echonl "ED => in InitSection"
endif
except
endsub
;
sub Gened.DoSection()
if this.trace then
echonl "ED => in DoSection, record #23":this.recordCount:' => ':this.currentRecord
endif
except
endsub
;
sub Gened.EndSection()
if this.trace then
echonl "ED => in EndSection"
endif
except
endsub
;
sub Gened.LevelBreakHeader(level)
if this.trace then
echonl "ED => in LevelBreakHeader:":level:' ':field(this.breakInfo{this.BREAKFIELDVAL, level}, "#FC", level)
endif
except
endsub
;
sub Gened.LevelBreakFooter(level)
if this.trace then
echonl "ED => in LevelBreakFooter:":level:' ':field(this.breakInfo{this.BREAKFIELDVALPREC, level}, "#FC", level):' last(':this.last:')'
endif
except
endsub
;
sub Gened.Execute()
declare un, moinsUn, breakVal, breakNum ; compteur des niveaux de rupture
let un = 1
let moinsUn = neg(1)
declare SVM
let SVM = "#FC"
let breakVal = ''
let breakNum = 0
;
do this.ParamSection()
;
do this.SetQuery()
;
do this.GetNextRecord()
;
let this.recordCount = 0
let this.breakCount = dcount(this.breakInfo, this.BREAKFIELDNUM)
;
do this.InitSection()
;
if not(this.last) then
loop
breakon this.last
if not(this.init) then
do this.GetNextRecord()
else
let this.init = @false
endif
;
foreach breakNum in un, this.breakCount
let breakVal = this.currentRecord{ this.breakInfo{this.BREAKFIELDNUM, breakNum} }
if breakNum > un then
let breakVal = this.breakInfo{this.BREAKFIELDVAL, breakNum - 1}:SVM:breakVal
endif
let this.breakInfo{this.BREAKFIELDVAL, breakNum} = breakVal
let this.breakInfo{this.BREAKDIFF, breakNum} = (this.breakInfo{this.BREAKFIELDVALPREC, breakNum} # breakVal)
endfor
;
if this.breakCount > 0 and (this.first or this.last or this.breakInfo{4, this.breakCount}) then
if not(this.first) then
foreach breakNum in this.breakCount, un, moinsUn
if this.last or this.breakInfo{this.BREAKDIFF, breakNum} then
do this.LevelBreakFooter(breakNum)
endif
endfor
endif
if not(this.last) then
foreach breakNum in un, this.breakCount
if this.first or this.breakInfo{this.BREAKDIFF, breakNum} then
let this.breakInfo{this.BREAKCOUNTER, breakNum} = 0
do this.LevelBreakHeader(breakNum)
endif
endfor
endif
let this.first = @false
endif
;
if not(this.last) then
foreach breakNum in un, this.breakCount
let this.breakInfo{this.BREAKCOUNTER, breakNum} = this.breakInfo{this.BREAKCOUNTER, breakNum} + 1
endfor
let this.recordCount = this.recordCount + 1
;
do this.DoSection()
;
let this.precRecord = this.currentRecord
let this.breakInfo{this.BREAKFIELDVALPREC} = this.breakInfo{this.BREAKFIELDVAL}
endif
endloop
endif
;
do this.EndSection()
;
do this.EndOfQuery()
;
except
; TODO
echonl "Exception in Execute"
endsub
;
class EdTest = {Gened}
;
sub EdTest.SetQuery()
declare path
let path = 'data.txt'
let this.data = ''
let this.line = 0
;
invoke file&get(path, this.data)
let this.data = change(this.data, '#0A', @fm)
;
let this.breakInfo = "3":@vm:5
;
do parent.SetQuery
except
endsub
;
sub EdTest.InitSection()
;echonl 'nb break: ':this.breakCount
do parent.InitSection
except
endsub
;
sub EdTest.GetNextRecord()
let this.line = this.line + 1
let this.currentRecord = this.data{this.line}
if this.currentRecord = '' then
let this.last = @true
else
let this.currentRecord = change(this.currentRecord, ';', @fm)
endif
;echonl "EdTest GetNextRecord: ":this.last:' / line ':this.line:' => ':this.currentRecord
except
endsub
;
declare ed
let ed = new EdTest
let ed.trace = @true
do ed.Execute()
;
except
;
echonl "Exception in main: ":@except
end
+19 -211
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,213 +27,10 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
env e;
long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, 10);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, 10, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
struct {
long blanc, nomregle, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} r;
void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
{
r.blanc = rg(e, regles, "blanc", tmp); // 1
r.nomregle = rg(e, regles, "nomregle", tmp); // 2
r.debut = rg(e, regles, "debut", tmp); // 3
r.fin = rg(e, regles, "fin", tmp); // 4
r.occ = rg(e, regles, "occ", tmp); // 5
r.infini = rg(e, regles, "infini", tmp); // 6
r.commentaire = rg(e, regles, "commentaire", tmp); // 7
r.intervalle = rg(e, regles, "intervalle", tmp); // 8
r.hexa = rg(e, regles, "hexa", tmp); // 9
r.car = rg(e, regles, "car", tmp); // 10
r.reste = rg(e, regles, "reste", tmp); // 11
}
long parse(Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours)
{
#define nreg(x) ((x)*2 > trav->mLg ? 0 : *(ent16 *)(trav->mPtr + (x)*2 - 2))
/* */
static int numlig = 0;
numlig++;
/* */
if(valex->mLg == 0)
return OK; /* ligne vide */
/* */
int nbres = dynDcount(&e, resultat, 10, DYN_NONE, DYN_NONE);
int nbval = dynDcount(&e, valex, cVM, 2, cFM);
ent16 regle;
dynSetLen(&e, trav, 0);
dynSetLen(&e, encours, 0);
for(int ival = nbval; ival > 0; ival--)
{
/* suppression des regles 1 et 7 (blanc et commentaire) */
dynField(&e, valex, tmp, 2, ival, cFM, cVM, 1);
regle = dynToNum(&e, tmp, DYN_FALSE, 0);
if(regle == r.blanc || regle == r.commentaire)
{
dynDel(&e, valex, 1, ival, cFM, cVM, 1);
dynDel(&e, valex, 2, ival, cFM, cVM, 1);
dynDel(&e, valex, 3, ival, cFM, cVM, 1);
}
else
{
if(dynCtrl(&e, trav, trav->mLg + 2, TRUE) != DYN_OK)
return DYN_ERR;
if(trav->mLg > 0)
memcopie(trav->mPtr + 2, trav->mPtr, trav->mLg);
*(ent16 *)(trav->mPtr) = regle;
dynSetLen(&e, trav, trav->mLg + 2);
}
}
//dynDel(&e, valex, 2, DYN_NONE, cFM, DYN_NONE, 1);
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
//for(int i=1;i<=trav->mLg/2;i++) printf("%d,",nreg(i)); printf("\n");
/* debut d'analyse des tokens : nomregle */
if(nreg(1) != r.nomregle)
{
dynField(&e, valex, tmp, 3, 1, cFM, cVM, 1);
printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* liste de et/ou */
for(ent16 n = 2;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == r.debut || regle == r.car) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : car ou debut et/ou attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
/* et */
if(n == 2)
dynStoreSz(&e, valex, 4, DYN_NONE, "", 0, cFM, DYN_NONE);
else
dynConcatSz(&e, valex, ";", 1);
/* */
if(regle == r.car)
{
/* 1 caractere = (1,1,car) (raccourci d'ecriture) */
dynConcatSz(&e, valex, "1,1,", 4);
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(&e, valex, tmp);
n++;
continue;
}
if(nreg(n+1) == r.occ && (nreg(n+2) == r.occ || nreg(n+2) == r.infini)) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : occurence min/max attendue %d\n", numlig, tmp->mPtr, n);
return DYN_ERR;
}
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcat(&e, valex, encours); // occmin
n++;
if(nreg(n) == r.infini)
dynConcatSz(&e, valex, "-1,", 3);
else
{
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcat(&e, valex, encours); // occmax
}
ent16 n1,n2,n3; char unefois[2] = {0};
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
while(n1 == r.car || n1 == r.hexa || ((n1 == r.car || n1 == r.hexa) && n2 == r.intervalle && (n3 == r.car || n3 == r.hexa)))
{
dynConcatSz(&e, valex, unefois, DYN_LGNONE);
if((n1 == r.car || n1 == r.hexa) && n2 == r.intervalle && (n3 == r.car || n3 == r.hexa))
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
if(n1 == 10)
dynConcat(&e, valex, tmp);
else
{
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
dynConcatSz(&e, valex, "-", 1);
n += 2;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
if(n3 == r.car)
dynConcat(&e, valex, tmp);
else
{
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
}
else if(n1 == r.car)
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(&e, valex, tmp);
}
else if(n1 == r.hexa)
{
n++;
dynField(&e, valex, tmp, 1, n, cFM, cVM, 1);
dynIconv(&e, tmp, encours, "X");
dynConcatSz(&e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
unefois[0] = ':';
}
if(unefois[0] == 0)
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : caractere/intervalle attendu\n", numlig, tmp->mPtr);
return DYN_ERR;
}
if(n1 == r.fin) ; else
{
dynField(&e, valex, tmp, 3, n, cFM, cVM, 1);
printf("Erreur ligne %dc%s : fin et/ou attendue\n", numlig, tmp->mPtr);
return DYN_ERR;
}
n += 2;
}
/* lecture nom regle en hexa */
dynField(&e, valex, tmp, 1, 1, cFM, cVM, 1);
dynIconv(&e, tmp, trav, "X");
trav->mPtr[trav->mLg - 1] = ','; /* exemple : begin,1,comment,2,... permet de faire un locate */
dynConcatSz(&e, trav, Int64ToSz(&e, nbres == 0 ? 1 : nbres, DYN_FALSE, 0), DYN_LGNONE);
dynStore(&e, resultat, 1, nbres == 0 ? 1 : nbres*2-1, trav, 10, ',');
/* */
dynField(&e, valex, tmp, 4, DYN_NONE, cFM, DYN_NONE, 1);
nbres = (nbres == 0 ? 2 : nbres + 1);
dynStoreSz(&e, resultat, nbres, DYN_NONE, tmp->mPtr, tmp->mLg, 10, DYN_NONE);
/* */
#undef nreg
return OK;
}
long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3)
{
dynSetLen(&e, elem2, 0); // token
@@ -313,6 +110,13 @@ long gen_c(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3
return OK;
}
long gen_h(Dynamic * resultat, Dynamic * elem1, Dynamic * elem2, Dynamic * elem3)
{
dynErase(&e, resultat, "\r"); /* nettoyage au cas ou fichier Windows */
dynChange(&e, resultat, "\n", "\\n", DYN_ALL);
return OK;
}
int main(int argc, char * argv[])
{
Dynamic fichier, valex, ligne, resultat, elem1, elem2, elem3, regles;
@@ -321,7 +125,7 @@ int main(int argc, char * argv[])
/* argument : fichier lex a convertir en format "interne" */
if(argc != 2)
{
printf("Usage: genlex <fichier>\n");
printf("Usage: wlex <fichier>\n");
exit(-3);
}
/* */
@@ -343,13 +147,12 @@ int main(int argc, char * argv[])
}
else
{
if(lire_regles_lex(&e, &regles, NULL) != DYN_OK)
if(lire_regles_lex(&e, &regles, "lexlex") != DYN_OK)
ret = -3;
}
if(ret == 0)
{
init_reg(&e, &regles, &elem1);
//printf("commentaire : %ld nomregle : %ld\n", r.commentaire, r.nomregle);
init_reg_lex(&e, &regles, &elem1); // elem1 = var tmp
//
dynErase(&e, &fichier, "\r");
dynRemove(&e, &fichier, NULL, 0, DYN_TRUE);
@@ -357,18 +160,23 @@ int main(int argc, char * argv[])
{
lex(&e, &regles, &ligne, &valex);
/* */
ret = parse(&valex, &resultat, &elem1, &elem2, &elem3);
ret = parse_lex(&e, &valex, &resultat, &elem1, &elem2, &elem3, 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);
dynFree(&e, &regles);
//
if(ret == 0)
{
dynLet(&e, &fichier, resultat.mPtr, resultat.mLg); // sauvegarde
// generer le code C a copier/coller dans genw.c
ret = gen_c(&resultat, &elem1, &elem2, &elem3);
printf("\nCode C genere : \n%s\n", resultat.mPtr);
//
// generer le code C a copier/coller dans lex_files.h
ret = gen_h(&fichier, &elem1, &elem2, &elem3);
printf("\nCode H genere : \n%s\n", fichier.mPtr);
}
}
dynFree(&e, &valex);
+672 -331
View File
File diff suppressed because it is too large. Load diff
+106 -42
View File
@@ -25,10 +25,19 @@
#include <string.h>
#include "langage.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
#ifndef WINLIB
/* met a jour le minimum de <env> pour pouvoir utiliser <dynamic.h> sans erreur... */
void init_env(env * e)
WAPIDECL void init_env(env * e)
{
int i,j,k;
/* endianess */
@@ -56,7 +65,7 @@ void init_env(env * e)
e->sep_subfield = '\xFD'; // cVM
}
char * copy_nom(env * e, const char * s)
WAPIDECL char * copy_nom(env * e, const char * s)
{
e->nom64[0] = 0;
e->nom64[1] = 0;
@@ -67,35 +76,30 @@ char * copy_nom(env * e, const char * s)
return e->nom;
}
/* CONTENU DE env->g
_arg : contient en FM les arguments de la ligne de commande a partir du nom du pcode wp ; @ARG
_file : contient le fichier source en cours, arborescence en FM celui en cours toujours en <1> ; @FILE
_bin : contient les noms des progs pcode en cours, arborescence d'appel des library en VM att 1 + "position" (1-n) binaddr en VM att 2, prog principal puis chaque appel de libr,
si plusieurs appel de la meme libr, le nom est repete ! le nom memorise est sans chemin ni extension (WBIN + .wp ajoute en auto); @BIN
exemple : prog VM libA VM libA VM libB FM 1 VM 2 VM 2 VM 3
_binaddr : contient les adresses debut et fin et compteur des sub/libr (pour eviter SIGSEGV lors dechargement library)
_env : contient les variables d'environnement "WBIN" FM "WSRC" ; @ENV
_prog : contient le nom du programme (apres begin dans le source), pas le nom du fichier
__xxx : var subroutine point d'entree pour le module xxx (dlsym)
a b c : variables globales
classe1 : classes, hashtables contenant =>
_class, ce qui permet de differencier une hashtable simple d'une classe
t u v : membres de la classe
objet1 : objet, instanciation d'une classe contenant =>
_class (oid FM _class de la classe), pour se differencier d'une hashtable normale
_oid : dernier n° d'objet traite (new,...) var @OID
WAPIDECL char * raz_nom(env * e)
{
e->nom64[0] = 0;
e->nom64[1] = 0;
e->nom64[2] = 0;
return e->nom;
}
_local : cree lors d'un do, contient la hashtable des vars de la sub (peut elle meme contenir une var _local pour
la sub appelee depuis la sub, etc.). Contenu de _local =>
_stack : var memorisant ce qu'il faut pour revenir a l'appelant
x y z : variables locales
*/
WAPIDECL int modFnIs(env * e, const char * fn, int lg)
{
// modifier l'endroit ou e->fn est mis a jour : verif fn64[0 1 2] est bien remis a zero avant la maj
ent64 f[3];
f[0] = 0; f[1] = 0; f[2] = 0;
if(lg < 1 || lg > 23)
return FALSE;
strncpy((char *)f, fn, lg);
return (e->fn64[0] == f[0] && e->fn64[1] == f[1] && e->fn64[2] == f[2]);
}
/* ************************************************************************** */
/* fonctions wrapper au cas ou on aurait besoin de ne plus utiliser certaines */
/* fonctions standards (malloc, etc.) */
void * memalloc(env * e, ent64 taille)
WAPIDECL void * memalloc(env * e, ent64 taille)
{
void * ptr;
taille += sizeof(ent64);
@@ -109,7 +113,11 @@ void * memalloc(env * e, ent64 taille)
}
*(ent64 *)ptr = taille;
//printf("P%p+\n", ptr);
#ifdef UNIX
return(ptr + sizeof(ent64));
#else
return((pointeur)ptr + sizeof(ent64));
#endif
}
else
{
@@ -119,11 +127,15 @@ void * memalloc(env * e, ent64 taille)
}
}
void memfree(env * e, void * ptr)
WAPIDECL void memfree(env * e, void * ptr)
{
if(ptr != NULL)
{
ptr -= sizeof(ent64);
#ifdef UNIX
ptr -= sizeof(ent64);
#else
(pointeur)ptr -= sizeof(ent64);
#endif
if(e != NULL)
{
e->mem_numb--;
@@ -135,7 +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;
@@ -153,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;
@@ -173,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;
@@ -216,14 +276,18 @@ void hex2(char * ch, int lg, int nbpl)
printf(" (%6d) %s\n", i, a);
}
#else
// Windows...
void init_env(env * e) {}
void hex(pointeur ch, int lg) {}
void hex2(char * ch, int lg, int nbpl) {}
void memcopie(void * dst, void * src, long nb) {}
void memfree(env * e, void * ptr) {}
void * memalloc(env * e, ent64 taille) {}
#endif
WAPIDECL void hex3(const char * p, long lg)
{
static char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
// affiche en hexa la chaine sur une ligne
printf("=> ");
for(long i = 0; i < lg; i++)
{
printf("%c%c ", hex[((unsigned char)p[i]) >> 4], hex[((unsigned char)p[i]) & 15]);
if(i % 32 == 31 && i < lg - 1)
printf("\n ");
else if(i % 8 == 7 && i < lg - 1)
printf(" | ");
}
printf("\n");
}
+17 -31
View File
@@ -23,45 +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);
/* CONTENU DE env->g
_arg : contient en FM les arguments de la ligne de commande a partir du nom du pcode wp ; @ARG
_file : contient le fichier source en cours, arborescence en FM celui en cours toujours en <1> ; @FILE
_bin : contient les noms des progs pcode en cours, arborescence d'appel des library en VM att 1 + "position" (1-n) binaddr en VM att 2, prog principal puis chaque appel de libr,
si plusieurs appel de la meme libr, le nom est repete ! le nom memorise est sans chemin ni extension (WBIN + .wp ajoute en auto); @BIN
exemple : prog VM libA VM libA VM libB FM 1 VM 2 VM 2 VM 3
_binaddr : contient les adresses debut et fin et compteur des sub/libr (pour eviter SIGSEGV lors dechargement library)
_env : contient les variables d'environnement "WBIN" FM "WSRC" ; @ENV
_prog : contient le nom du programme (apres begin dans le source), pas le nom du fichier
__xxx : var subroutine point d'entree pour le module xxx (dlsym)
a b c : variables globales
classe1 : classes, hashtables contenant =>
_class, ce qui permet de differencier une hashtable simple d'une classe
t u v : membres de la classe
objet1 : objet, instanciation d'une classe contenant =>
_class (oid FM _class de la classe), pour se differencier d'une hashtable normale
_oid : dernier n° d'objet traite (new,...) var @OID
_local : cree lors d'un do, contient la hashtable des vars de la sub (peut elle meme contenir une var _local pour
la sub appelee depuis la sub, etc.). Contenu de _local =>
_stack : var memorisant ce qu'il faut pour revenir a l'appelant
x y z : variables locales
*/
WAPIDECL char * copy_nom(env * e, const char * s);
WAPIDECL 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);
#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
+32
View File
@@ -0,0 +1,32 @@
/* **********************************************
__ __ __
\ \/ \/ / 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);
+60 -273
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.
@@ -40,6 +40,8 @@
#include "langage.h"
#include "dynamic.h"
#include "hash.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
@@ -52,262 +54,16 @@ static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
return err == OK ? OK : EX_MODERR;
}
static void encodageMD2(char * entree, ent64 longueur, char * sortie)
{
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;
@@ -333,7 +89,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -346,7 +102,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//*** code specifique ici
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
@@ -355,55 +111,86 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
if(param1 == NULL)
exc = EX_MODETAT;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
if(param1->type == VAR_NUMBER)
if(param1 == NULL)
exc = EX_MODETAT;
else if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "MD2", 3) == 0)
else if(modFnIs(e, "MD2", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD2(param1->mPtr, param1->lg, param2->mPtr);
encodageMD2(e, param1, param2);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "MD4", 3) == 0)
else if(modFnIs(e, "MD4", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD4(param1->mPtr, param1->lg, param2->mPtr);
encodageMD4(e, param1, param2);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD5", 3))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageMD5(e, param1, param2);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "Sha1", 4))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
encodageSha1(e, param1, param2);
}
}
/* ----------------------------------------------------------------------------------------------- */
+695
View File
@@ -0,0 +1,695 @@
/* **********************************************
__ __ __
\ \/ \/ / 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);
}
+149 -29
View File
@@ -27,31 +27,64 @@
#include "langage.h"
#include "var.h"
#include "hashtable.h"
#include "dynamic.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
// =============== PRIVATE ========================================================================
static entry * calc_entry(char * val, var * varht)
{
/* fonctionne avec des noms de 24 octets max (val) */
/* algo de D. B e r n s t e i n */
ent64 hash = 5381;
/* optimiser en travaillant sur 3 qword ou 6 dword mais
pbm les petites chaines donneront des modules idem */
/* ent64 * p = (ent64 *)val;
hash += *p++;
hash = hash + (hash << 5) + *p++;
hash = hash + (hash << 5) + *p;*/
for(int iCle = 0; iCle < 24; iCle++)
if(val[iCle])
hash = hash + (hash<<5) + val[iCle]; /* hash*33 */
else
break; // stop au premier \0
ent64 hash;
/* algo de D. B e r n s t e i n / M u r m u r h a s h 6 4 */
/* autre algo */
if(0) {
ent64 * p = (ent64 *)val;
ent64 k = *p++;
ent64 m = 0xc6a4a7935bd1e995ull;
hash = 5381 ^ (24 * m);
//
k *= m;
k ^= k >> 47;
k *= m;
hash ^= k;
hash *= m;
k = *p++; /* */
k *= m;
k ^= k >> 47;
k *= m;
hash ^= k;
hash *= m;
k = *p; /* */
k *= m;
k ^= k >> 47;
k *= m;
hash ^= k;
hash *= m;
}
/* */
if(1) {
hash = 5381;
for(int iCle = 0; iCle < 24; iCle++)
if(val[iCle])
hash = hash + (hash<<5) + val[iCle]; /* hash*33 */
else
break; // stop au premier \0
}
return((entry *)(varht->ptr + (varht->separateur * (hash % varht->modulo))));
}
// =============== PUBLIC ========================================================================
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
{
/* READ renvoi le ptr sur la var (ne fait pas une copie de la var)
WRITE copie la var (si pas trouve ou trouve mais pointeurs differents)
@@ -65,7 +98,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) | */
@@ -96,6 +135,7 @@ 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 */
@@ -107,6 +147,7 @@ void hashtable_do(env * e, int action, var * varht, char * nom, var ** v)
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,11 +190,17 @@ 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);
}
}
void hashtable_select(env * e, var * varht)
WAPIDECL var * hashtable_lastitemwritten(var * varht)
{
return ((entry *)varht->ptr)->pvar;
}
WAPIDECL void hashtable_select(env * e, var * varht)
{
/* les 4 variables necessaires seront mises dans le groupe 0, premiere entree (celle servant au chainage) */
/* dans la variable (content, inutilise) : */
@@ -169,10 +216,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++)
{
@@ -208,7 +256,7 @@ int hashtable_next(env * e, var * varht, char * nom, var ** v)
return FALSE;
}
void hashtable_free_ovf(env *e, var * varht)
WAPIDECL void hashtable_free_ovf(env *e, var * varht)
{
/* libere les overflow de la hash table */
/* pour chaque entree, chainage avant puis liberation en revenant en arriere */
@@ -231,7 +279,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;
@@ -243,11 +291,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;
@@ -256,29 +304,96 @@ 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 */
entry * pchain_first; /* premier bloc */
ent64 groupe; /* groupe en cours */
ent64 occ, tot; /* taille occupee, totale */
ent64 occ, tot, nb; /* taille occupee, totale, nb items */
char * ptrClass = NULL;
/* affiche le contenu d'une hashtable */
if(varht == NULL)
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;
nb = 0;
pchain = (entry *)varht->ptr;
for(groupe = 0; groupe < varht->modulo; groupe++)
{
@@ -312,10 +427,11 @@ void hashtable_printdebug(env * e, var * varht, int detail)
else
printf("%c", e->var_car[pentry->content.type % 10]);
/* */
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, "_class", 6) == 0 && ! ptrClass)
if(varht->type == VAR_OBJECT && strncmp((char *)&pentry->nom1, GUV_CLASS, 6) == 0 && ! ptrClass)
ptrClass = pentry->content.mPtr;
/* */
occ += sizeof(entry);
nb++;
}
pentry++;
}
@@ -325,8 +441,12 @@ void hashtable_printdebug(env * e, var * varht, int detail)
pchain = (entry *)((ent64)pchain_first + varht->separateur);
}
if(ptrClass)
printf("_class : %s\n", ptrClass);
printf("taille totale=%lld, occupee=%lld (taux %lld%%)\n", tot, occ, occ * 100 / tot);
{
dynLet(e, &e->tmp_dynamic, ptrClass, DYN_LGNONE);
dynReplace(e, &e->tmp_dynamic, cFM, ':');
printf("%s %s\n", GUV_CLASS, e->tmp_dynamic.mPtr);
}
printf("taille totale=%lld, occupee=%lld (taux %lld%%), nb item=%lld\n", tot, occ, occ * 100 / tot, nb);
}
/* ********************************************** */
+12 -7
View File
@@ -23,14 +23,19 @@
#ifndef HASHTABLE_H
#define HASHTABLE_H
void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
void hashtable_select(env * e, var * varht);
int hashtable_next(env * e, var * varht, char * nom, var ** v);
void hashtable_free_ovf(env *e, var * varht);
void hashtable_clear(env *e, var * varht);
long hashtable_count(env *e, var * varht);
#include "apidecl.h"
void hashtable_printdebug(env * e, var * varht, int detail);
WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var ** v);
WAPIDECL void hashtable_select(env * e, var * varht);
WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v);
WAPIDECL void hashtable_free_ovf(env *e, var * varht);
WAPIDECL void hashtable_clear(env *e, var * varht);
WAPIDECL long hashtable_count(env *e, var * varht);
WAPIDECL var * hashtable_lastitemwritten(var * varht);
WAPIDECL void hashtable_serialize(env * e, var * varht, var * out);
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail);
/* ********************************************** */
#endif
+67
View File
@@ -0,0 +1,67 @@
/* **********************************************
__ __ __
\ \/ \/ / 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,
/* code retour */
HTTP_REQUEST_ERROR = -1,
HTTP_REQUEST_INPROGRESS = 0,
HTTP_REQUEST_COMPLETE = 1,
HTTP_REQUEST_EXPECTCONTINUE = 2
};
WAPIDECL void Init(env * e, modCtxHttp * ctx);
WAPIDECL void End(env * e, modCtxHttp * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxHttp * ctx, Dynamic * data);
WAPIDECL long MakeExpect100(env * e, modCtxHttp * ctx, Dynamic * reponse);
WAPIDECL long MakeResponse(env * e, modCtxHttp * ctx, long cr, Dynamic * reponse);
+155
View File
@@ -0,0 +1,155 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 "http.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modCtxHttp ctxHttp;
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
Init(e, &p_etat->ctxHttp);
//
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
End(e, &p_etat->ctxHttp);
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
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
{
long cr = ExtractMessage(e, &p_etat->ctxHttp, param1);
param2->num = cr * NUM_FACTEUR;
if(cr == HTTP_REQUEST_COMPLETE)
dynSetAs(e, param3, &p_etat->ctxHttp.content);
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
+338
View File
@@ -0,0 +1,338 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 Init(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 End(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)
{
/* 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 == 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 */
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", 3, 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
{
/* 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;
}
+192
View File
@@ -0,0 +1,192 @@
void instr_unassemble(env * e, pointeur debutBin, ent64 nolig)
{
char * l = libInstr + e->instr * 4;
//
if(e->fin - debutBin > 9999)
printf("[%d:%08lld-%08lld-%08lld ex %08lld]", e->bin_indice, (ent64)(e->debut - debutBin), (ent64)(e->si - 1 - debutBin), (ent64)(e->fin - debutBin), (ent64)(e->si_except - debutBin));
else
printf("[%d:%04lld-%04lld-%04lld ex %04lld]", e->bin_indice, (ent64)(e->debut - debutBin), (ent64)(e->si - 1 - debutBin), (ent64)(e->fin - debutBin), (ent64)(e->si_except - debutBin));
//
printf(" line %06lld ex-ex %04lld > %c%c%c%c ", nolig, e->except_ex, *l, *(l+1), *(l+2), *(l+3));
//
ent64s d8;
int d3;
octet d1;
pointeur p = e->si;
//
switch(e->instr)
{
/* 2 bytes w opcode (instr d1) */
case IN_VERS:
case IN_PART:
case IN_PREC:
d1 = lire8(p);
printf("%d", d1);
break;
/* special 2 bytes w opcode */
case IN_COMP:
d1 = lire8(p);
if(d1 < CMP_EQ || d1 > CMP_FOR)
printf("??? (%d)", d1);
else
{
l = libComp + d1 * 3 - 3;
printf("%c%c%c", *l, *(l+1), *(l+2));
}
break;
case IN_PSHA:
dynLet(e, &e->tmp_dynamic, VARSYS, DYN_LGNONE);
d1 = lire8(p);
d3 = dynLocateSz(e, &e->tmp_dynamic, Int32ToSz(d1, FALSE, 0), ',', 2, ';');
if(d3 > 0)
{
d3 = dynExtractPos(e, &e->tmp_dynamic, 1, d3, ';', ',');
if(d3 > 0)
printf("%.*s", d3, &e->tmp_dynamic.mPtr[e->tmp_dynamic.mInternal]);
}
if(d3 <= 0)
printf("?? (%d)\n", d1);
break;
/* 2+lg bytes w opcode (instr lg valeur) */
case IN_DECL:
case IN_CALL:
case IN_PARM:
case IN_MODL:
case IN_PVAR:
case IN_PVAH:
case IN_DSET:
case IN_DSTO:
case IN_VLET:
case IN_DCAT:
case IN_NLET:
case IN_INCL:
case IN_PNAM:
case IN_CLIB:
case IN_PVAI:
case IN_CPSH:
case IN_PHDE:
case IN_PIDE:
case IN_PHDH:
case IN_PIDH:
case IN_PHDO:
case IN_PIDO:
case IN_PHDN:
case IN_PIDN:
case IN_PHDV:
case IN_PIDV:
case IN_PVHD:
case IN_PVID:
case IN_DEXH:
case IN_DEXI:
case IN_DESH:
case IN_DESI:
case IN_DEZH:
case IN_DEZI:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* 3+lg bytes w opcode (instr lg valeur) */
case IN_DCMP:
d1 = lire8(p++);
if(d1 < CMP_EQ || d1 > CMP_NOT)
printf("??? (%d) ", d1);
else
{
l = libComp + d1 * 3 - 3;
printf("%c%c%c ", *l, *(l+1), *(l+2));
}
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* 5+lg bytes w opcode (instr lg valeur) */
case IN_SUBR:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
d3 = lire24(p) + (e->si - 1 - debutBin);
printf(" %d", d3);
break;
case IN_PHDS:
case IN_PIDS:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
d3 = lire24(p);
printf(" %d", d3);
break;
/* 4 bytes w opcode (instr d3) */
case IN_JUMP:
case IN_JMPF:
case IN_JMPT:
d3 = lire24(e->si) + (e->debut - debutBin);
printf("%d", d3);
break;
case IN_BEXC:
d3 = lire24(e->si) + (e->si - 1 - debutBin);
printf("%d", d3);
break;
case IN_SRCL:
case IN_THRW:
d3 = lire24(e->si);
printf("%d", d3);
break;
/* 9 bytes w opcode */
case IN_PSHC:
d8 = lire64(p);
printf("%lld\n", d8);
break;
/* 3+lg1+lg2 bytes w opcode */
case IN_CLAS:
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
printf(":");
d1 = *p++;
if(d1 > 0)
for( ;d1;d1--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* 4+d3 bytes w opcode */
case IN_SDBG:
d3 = *p++;
if(d3 > 0)
for( ;d3;d3--)
printf("%c", *p++);
else
printf("_"); // marque une longueur à 0
break;
/* one byte w opcode (and unknown opcode...) */
default:
break;
}
printf("\n");
}
+41 -13
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"
"PSH4" "PSH5" "PSH6" "PSH7" "PSH8" "PSH9" "PSHA" "SQRT" "IEXP" "CLIB" /* 50-59 */
"PVAI" "DIVE" "MODN" "INPT" "PVAT" "TYPO" "PSHT" "CRAZ" "CPSH" "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" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" /* 110-119 */
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"DESH" "DESI" "DEZV" "DEZH" "DEZI" "SDBG" "PHDN" "PIDN" "SADV" "VLET" /* 110-119 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "SSRC" "SSCS" "xxxx" "xxxx" "xxxx" /* 126 */
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
@@ -60,8 +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[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "FOR"};
#define IS_VERS "\x00"
#define IN_VERS 0
@@ -138,8 +140,8 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
#define IN_DCMP 34
#define IS_DSTO "\x23"
#define IN_DSTO 35
#define IS_VLET "\x24"
#define IN_VLET 36
#define IS_LETV "\x24"
#define IN_LETV 36
#define IS_DCAT "\x25"
#define IN_DCAT 37
#define IS_DTON "\x26"
@@ -182,10 +184,10 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
#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
@@ -304,13 +306,39 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
#define IN_DEZH 113
#define IS_DEZI "\x72"
#define IN_DEZI 114
#define IS_SDBG "\x73"
#define IN_SDBG 115
#define IS_PHDN "\x74"
#define IN_PHDN 116
#define IS_PIDN "\x75"
#define IN_PIDN 117
#define IS_SADV "\x76"
#define IN_SADV 118
#define IS_VLET "\x77"
#define IN_VLET 119
#define IS_PHDV "\x78"
#define IN_PHDV 120
#define IS_PIDV "\x79"
#define IN_PIDV 121
#define IS_HCOU "\x7A"
#define IN_HCOU 122
#define IS_PVHD "\x7B"
#define IN_PVHD 123
#define IS_PVID "\x7C"
#define IN_PVID 124
#define IS_SSRC "\x7D"
#define IN_SSRC 125
#define IS_SSCS "\x7E"
#define IN_SSCS 126
#define IS_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 -27
View File
@@ -1,3 +1,25 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
@@ -29,39 +51,34 @@ typedef struct
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMODJSON_MEM 106
#define EXMODJSON_DECODE_INCORRECT_CHAR 101
#define EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED 102
#define EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED 103
#define EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED 104
#define EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER 105
#define EXMODJSON_DECODE_UNTERMINATED_STRING 107
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT 108
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY 109
#define EXMODJSON_DECODE_UNEXPECTED_KEY 110
#define EXMODJSON_DECODE_UNEXPECTED_VALUE 111
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT 112
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT 113
#define EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY 114
#define EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON 115
enum {
EXMODJSON_MEM = 106,
EXMODJSON_DECODE_INCORRECT_CHAR = 101,
EXMODJSON_DECODE_KEYWORD_TRUE_EXPECTED = 102,
EXMODJSON_DECODE_KEYWORD_FALSE_EXPECTED = 103,
EXMODJSON_DECODE_KEYWORD_NULL_EXPECTED = 104,
EXMODJSON_DECODE_INCORRECT_CHAR_IN_NUMBER = 105,
EXMODJSON_DECODE_UNTERMINATED_STRING = 107,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_OBJECT = 108,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_START_ARRAY = 109,
EXMODJSON_DECODE_UNEXPECTED_KEY = 110,
EXMODJSON_DECODE_UNEXPECTED_VALUE = 111,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_NEXT = 112,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_OBJECT = 113,
EXMODJSON_DECODE_UNEXPECTED_TOKEN_END_ARRAY = 114,
EXMODJSON_DECODE_UNEXPECTED_ENDOFJSON = 115
};
/*
Le decodage a besoin de mEncodeCle mEncodeValeur et la position de l'erreur si erreur (3 parametres ; en entree la position le flag "NoDQuote"). L'erreur est le code retour.
L'encodage a besoin de mEncode, mId, flag NoDQuote (3 parametres)
*/
int jsonInit(env * e, modContextJson * ctx);
int jsonEnd(env * e, modContextJson * ctx);
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
typedef struct {
var * KeyList, * CurrentKey, * Name, * Value, * DecodeCle, * DecodeValue; // Dynamic
var * KeyField, * KeyItem, * KeyCount, * ItemCount, * Id, * Parent, * IdKey, * ParentKey, * ValuePresent, * Begin; // Number
// output: Name Value IdKey IdParent ValuePresent
} treefetch; // contenu de la var hashtable passee en param
int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonInit(env * e, modContextJson * ctx);
WAPIDECL int jsonEnd(env * e, modContextJson * ctx);
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3);
/*
+12 -13
View File
@@ -43,13 +43,12 @@ static int setError(modEtat * p, int err)
return err == OK ? OK : EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -73,7 +72,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -87,7 +86,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = setError(p_etat, jsonInit(e, &p_etat->jsonCtx));
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
exc = setError(p_etat, jsonEnd(e, &p_etat->jsonCtx));
@@ -95,7 +94,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -110,7 +109,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -126,7 +125,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "decode", 6) == 0)
else if(modFnIs(e, "decode", 6))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
@@ -141,7 +140,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "print", 5) == 0)
else if(modFnIs(e, "print", 5))
{
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
@@ -154,14 +153,14 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = setError(p_etat, jsonPrint(e, &p_etat->jsonCtx, param1, param2, param3));
}
}
else if(strncmp(e->fn, "treeFetch", 9) == 0)
else if(modFnIs(e, "treeFetch", 9))
{
if(param1 == NULL)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else
{
/* param1 must be a hash table (input) */
if(param1->type != VAR_HASHTABLE)
if(param1->type != VAR_HASHTABLE || param2->type != VAR_NUMBER)
exc = EX_MODPARAM; // bad type of parameter 1
else
exc = setError(p_etat, jsonTreeFetch(e, &p_etat->jsonCtx, param1, param2, param3));
+177 -61
View File
@@ -1,3 +1,25 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -7,8 +29,16 @@
#include "var.h"
#include "hashtable.h"
#define LF 10
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ------------------------------------------ */
#define CAR_DQUOTE '"'
#define CAR_MARQUE_CLE ':'
#define CAR_DEBUT_OBJET '{'
@@ -25,23 +55,27 @@
#define STR_FIN_TABLEAU "]"
#define STR_SUIVANT ","
#define DEBUT_FICHIER 0
#define VALEUR_CHAINE 1
#define VALEUR_NOMBRE 2
#define VALEUR_CLE 3
#define DEBUT_OBJET 4
#define FIN_OBJET 5
#define DEBUT_TABLEAU 6
#define FIN_TABLEAU 7
#define SUIVANT 8
#define FIN_FICHIER 9
enum {
DEBUT_FICHIER = 0,
VALEUR_CHAINE = 1,
VALEUR_NOMBRE = 2,
VALEUR_CLE = 3,
DEBUT_OBJET = 4,
FIN_OBJET = 5,
DEBUT_TABLEAU = 6,
FIN_TABLEAU = 7,
SUIVANT = 8,
FIN_FICHIER = 9,
#define ENCODE_OK 1
#define ENCODE_ERREUR 0
ENCODE_OK = 1,
ENCODE_ERREUR = 0,
LF = 10
};
/* =================================================================================== */
/* --------- JSON C --------- */
/* --------- PRIVATE --------- */
static void ConcatValue(env * e, modContextJson * ctx, char c)
{
char car[2];
@@ -484,52 +518,83 @@ static int MakePrintable(env * e, modContextJson * ctx, var * DecodeBrut, var *
return OK;
}
/* NOT USED
static void InitTreeFetch()
{
GetNextTreeFetch(NULL, NULL, NULL, NULL, NULL);
}
*/
typedef struct {
var * KeyList, * CurrentKey, * Name, * Value, * DecodeCle, * DecodeValue; // Dynamic
var * KeyField, * KeyItem, * KeyCount, * ItemCount, * Id, * Parent, * IdKey, * ParentKey, * ValuePresent; // Number
// output: Name Value IdKey ParentKey ValuePresent
} treefetch; // contenu de la var hashtable passee en param
/*
static int GetNextTreeFetch(env * e, modContextJson * ctx, long * parentKey, long * idKey, Dynamic * name, Dynamic * value, int * valuePresent)
static int GetNextTreeFetch(env * e, treefetch * tree)
{
static Dynamic KeyList, CurrentKey; // hash entree
static long KeyField, KeyItem, KeyCount, ItemCount, id, parent; // hash entree
char ArrayMark = '#';
//
if(parentKey == NULL && idKey == NULL && name == NULL && value == NULL && valuePresent == NULL)
{
// InitTreeFetch
KeyList.DeleteAllContent();
KeyField = 1; // current field in mDecodeCle
KeyItem = 1; // current part of path of current field
mDecodeCle.SetSubFieldDelimiter(cSVM);
KeyCount = mDecodeCle.CountField();
ItemCount = mDecodeCle.CountSubField(KeyField);
id = 1;
parent = 0;
return true;
}
if(parentKey == nullptr || idKey == nullptr || name == nullptr || value == nullptr || valuePresent == nullptr)
return false; // security
//
if(KeyField == 0)
return false; // false = fini
//
if(tree->KeyField->num == 0)
return FALSE; // false = fini
// check here if empty json
if(KeyCount == 0 && ItemCount == 0)
if(tree->KeyCount->num == 0 && tree->ItemCount->num == 0)
{
// single value json
name->SetAs("#");
mDecodeValeur.ExtractField(1, *value, 1);
*parentKey = parent;
*idKey = id;
*valuePresent = true;
KeyField = 0;
return true;
dynLet(e, tree->Name, "#", 1);
dynField(e, tree->DecodeValue, tree->Value, 1, DYN_NONE, cVM, cSVM, 1);
tree->ParentKey->num = tree->Parent->num;
tree->IdKey->num = tree->Id->num;
tree->ValuePresent->num = NUM_UN;
tree->KeyField->num = 0;
return TRUE;
}
//
for(long pos;;)
{
if(tree->KeyItem->num == tree->ItemCount->num)
{
// value found
tree->ParentKey->num = tree->Parent->num;
tree->IdKey->num = tree->Id->num;
dynField(e, tree->DecodeCle, tree->Name, tree->KeyField->num, tree->KeyItem->num, cVM, cSVM, 1);
dynReplace(e, tree->Name, cTM, ArrayMark);
dynField(e, tree->DecodeValue, tree->Value, tree->KeyField->num, DYN_NONE, cVM, DYN_NONE, 1);
tree->ValuePresent->num = TRUE; // means send a value
// prepare next call
if(tree->KeyField->num >= tree->KeyCount->num)
tree->KeyField->num = 0;
else
{
tree->Id->num++;
tree->Parent->num = 0;
tree->KeyField->num++;
tree->KeyItem->num = 1;
tree->ItemCount->num = dynDcount(e, tree->DecodeCle, cSVM, tree->KeyField->num, cVM);
}
return TRUE;
}
dynField(e, tree->DecodeCle, tree->CurrentKey, tree->KeyField->num, 1, cVM, cSVM, tree->KeyItem->num);
pos = dynLocateSz(e, tree->KeyList, tree->CurrentKey->mPtr, cVM, 1, cFM);
if(pos < 1)
{
// new path
dynIns(e, tree->KeyList, 1, 1, tree->CurrentKey, cFM, cVM);
dynInsNumber(e, tree->KeyList, 2, 1, tree->Id->num, cFM, cVM);
// part of path found
tree->ParentKey->num = tree->Parent->num;
tree->IdKey->num = tree->Id->num;
dynField(e, tree->DecodeCle, tree->Name, tree->KeyField->num, tree->KeyItem->num, cVM, cSVM, 1);
dynReplace(e, tree->Name, cTM, ArrayMark);
tree->ValuePresent->num = NUM_ZERO; // means no value here (part of path)
// prepare next call
tree->Parent->num = tree->Id->num++;
tree->KeyItem->num++;
//
return TRUE;
}
// loop to next part of path
dynExtractSubField(e, tree->KeyList, 2, pos, tree->Parent);
tree->KeyItem->num++;
}
//
return TRUE; //ok, but should never reach this point...
}
/*
for(long pos;;)
{
if(KeyItem == ItemCount)
@@ -577,12 +642,10 @@ static int GetNextTreeFetch(env * e, modContextJson * ctx, long * parentKey, lon
KeyList.ExtractSubField(2, pos, parent);
KeyItem++;
}
//
return true; //ok, but should never reach this point...
}*/
*/
/* =================== PUBLIC ========================== */
int jsonInit(env * e, modContextJson * ctx)
WAPIDECL int jsonInit(env * e, modContextJson * ctx)
{
int cr = OK;
//cr += dynInit(e, &ctx->mKeyList, DYN_LGMIN);
@@ -607,7 +670,7 @@ int jsonInit(env * e, modContextJson * ctx)
return (cr == OK ? OK : EXMODJSON_MEM);
}
int jsonEnd(env * e, modContextJson * ctx)
WAPIDECL int jsonEnd(env * e, modContextJson * ctx)
{
//dynFree(e, &ctx->mKeyList);
//dynFree(e, &ctx->mCurrentKey);
@@ -619,23 +682,76 @@ int jsonEnd(env * e, modContextJson * ctx)
return OK;
}
int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonDecode(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
{
return Decode(e, ctx, param1->mPtr, param2, param3);
}
int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonPrint(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
{
char value[4] = " : \0", path = '/', index = '@';
//
return MakePrintable(e, ctx, param1, param2, param3, path, index, value);
}
int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
WAPIDECL int jsonTreeFetch(env * e, modContextJson * ctx, var * param1, var * param2, var * param3)
{
// KeyList, CurrentKey, Name, Value, DecodeCle, DecodeValue; // Dynamic
// KeyField, KeyItem, KeyCount, ItemCount, Id, Parent, IdKey, ParentKey, ValuePresent, Begin; // Number
treefetch tree;
// KeyField, KeyItem, KeyCount, ItemCount, Id, Parent, IdKey, ParentKey, ValuePresent; // Number
treefetch tree; // contexte specifique a chaque appel
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeCle"), &tree.DecodeCle);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "DecodeValue"), &tree.DecodeValue);
if(tree.DecodeCle == NULL || tree.DecodeValue == NULL)
{
param2->num = NUM_UN;
return OK; // TODO erreur
}
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
if(tree.KeyList == NULL)
{
// init vars
var * v = &e->int_dynamic;
dynSetLen(e, &e->int_dynamic, 0);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyList"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "CurrentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Name"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Value"), &v);
v = &e->int_number;
v->num = 1;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyField"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyItem"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Id"), &v);
v->num = 0;
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "Parent"), &v);
v->num = dynDcount(e, tree.DecodeCle, cVM, DYN_NONE, DYN_NONE);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "KeyCount"), &v);
v->num = dynDcount(e, tree.DecodeCle, cSVM, 1, cVM);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ItemCount"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "IdKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ParentKey"), &v);
hashtable_do(e, HASH_WRITE, param1, copy_nom(e, "ValuePresent"), &v);
}
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyList"), &tree.KeyList);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CurrentKey"), &tree.CurrentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Name"), &tree.Name);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Value"), &tree.Value);
//
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyField"), &tree.KeyField);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyItem"), &tree.KeyItem);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "KeyCount"), &tree.KeyCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ItemCount"), &tree.ItemCount);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Id"), &tree.Id);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Parent"), &tree.Parent);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "IdKey"), &tree.IdKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ParentKey"), &tree.ParentKey);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "ValuePresent"), &tree.ValuePresent);
/* */
//hashtable_printdebug(e, param1, 1);
if(GetNextTreeFetch(e, &tree)) // TRUE = pas fini
param2->num = NUM_ZERO; // var <fin>
else
param2->num = NUM_UN;
return OK;
}
+2064 -1835
View File
File diff suppressed because it is too large. Load diff
+155 -86
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -23,16 +23,20 @@
#ifndef LANGAGE_H
#define LANGAGE_H
#define VERSION 1 // version "max" gere du pcode => version du "langage"
enum {
VERSION = 1 // version "max" gere du pcode => version du "langage"
};
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define W_LITTLE_ENDIAN 1
#define W_BIG_ENDIAN 0
#define W_DEFAULT_ENDIAN 2 // celle de la plateforme d'execution
enum {
W_LITTLE_ENDIAN = 1,
W_BIG_ENDIAN = 0,
W_DEFAULT_ENDIAN = 2 // celle de la plateforme d'execution
};
typedef unsigned char octet;
typedef octet * pointeur; /* et pas "void *" ... */
@@ -44,7 +48,11 @@ typedef int ent32s;
typedef long long ent64s;
typedef unsigned short ent16;
#ifndef UNIX
typedef ent64s ent128s; // sous windows, pas de __int128 : TODO a changer pour des calculs corrects
#else
typedef __int128 ent128s; // temporaire pour les calculs intermediaires (multiplication)
#endif
#define NUM_MIN -999999999999999999ll
#define NUM_MAX 999999999999999999ll
@@ -69,31 +77,37 @@ 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,
WCP_DEFAULT = WCP_ASCII // WIN1252 ? UTF8 ?
};
typedef struct {
union {
ent64 type; /* type defini ci-dessus */
//union {
ent16 type; /* type defini ci-dessus (au lieu de ent64) */
//pointeur local; /* pour memo _stack */
ent16 typv[4]; /* permet de gerer des options par type : code page pour dynamic, unite/devise pour number, fuseau si number/date etc. */
ent16 codePage; /* pour dynamic */
ent16 typv[2]; /* permet de gerer des options par type : unite/devise pour number, fuseau si number/date etc. */
/* typv[0] = type; typv[1] = code page/unite/fuseau typv[2] typv[3] usage futur (langue, pays) */
};
//};
union {
number num; /* si type = 1 VAR_NUMBER */
pointeur ptr; /* si type = 2 a 8 : pointeur vers les donnees variables / variable si "PARAM" / si->debut si SUBROUTINE / ptr si module */
@@ -156,9 +170,6 @@ typedef struct {
v->ptr v->ptr v->misc
*/
#define BUF_LGBLOC 8192 /* multiple de 32 sinon pile d'elements 8 et 16 octets KO */
#define BUF_LGWRITE_MAX 4000 /* doit etre au maxi BUF_LGBLOC - 3 */
typedef struct {
/* buffer servant de stack pour number et string */
number num; /* nombre si str == NULL */
@@ -181,61 +192,74 @@ typedef struct {
/* vrai buffer read = position a lire dans les donnees (a ajouter a ptr) ou prochaine position a ecrire (pile calcul et appel) */
/* vrai buffer write = position a ecrire dans les donnees (a ajouter a ptr) ; si READ=WRITE : vide ! ou utilise en interne si pile */
#define OID_MAX 9999999999999999ll /* pour que l'OID reste sur 16 chiffres : 16 neufs ici */
#define OID_MAX 999999999999999ll /* pour que l'OID reste sur 16 chiffres : 15 neufs ici, pour qu'un oid commence toujours par 0 ! */
#define OID_MIN 100ll /* demarrage a 100 pour eviter les nombres trop petits */
#define CLASS_BASE "Base" /* classe mere de toutes les classes */
#define MAX_PARAM 8 /* nb maxi de parametres d'une sub/methode */
enum {
BUF_LGMINBLOC = 16384, /* multiple de 32 sinon pile d'elements 8 et 16 octets KO, lgmax message = lg buffer / 32 (512 octets ici) */
MAX_PARAM = 8, /* nb maxi de parametres d'une sub/methode */
#define HASH_READ 1
#define HASH_DELETE 2
#define HASH_WRITE 3
HASH_READ = 1,
HASH_DELETE = 2,
HASH_WRITE = 3,
#define NOK -1 /* quand pas une exception */
NOK = -1 /* quand pas une exception */
};
//
// 000 a 999 : erreur systeme
// 1000 a 9999 : reserve aux modules systeme
// 1000 a 1099 : module "db"
//
#define OK 0
#define EX_DIV0 1 /* exceptions */
#define EX_MEM 2 /* memalloc ko */
#define EX_BUFOVF 3 /* depassement de capacite du buffer */
#define EX_IO 4 /* erreur d'entree/sortie (leture fichier...) */
#define EX_END 5 /* adresse du code hors prog/sub */
#define EX_LGNOM 6 /* lg nom variable incorrecte (de 1 a 24 inclus) */
#define EX_TYPVAR 7 /* type variable non attendu */
#define EX_NULLOCAL 8 /* hashtable locale null et pas dans le code "global" */
#define EX_NOVAR 9 /* nom de variable inconnu */
#define EX_MODOPEN 10 /* erreur ouverture module (dlopen) */
#define EX_MODDSYM 11 /* fonction execModule non trouvee dans le module (dsym) */
#define EX_NOSTACK 12 /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
#define EX_NAVAR 13 /* la variable n'est pas du bon type / not available */
#define EX_NOADVAR 14 /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
#define EX_NAVERS 15 /* version de pcode non prise en charge par le "compilateur" */
#define EX_MODNAME 16 /* le nom d'appel du module est incorrect */
#define EX_DYNERR 17 /* erreur dans la manipulation des chaines */
#define EX_MODFUNC 18 /* le code function du module est inconnu */
#define EX_MODPARAM 19 /* le parametre donne au module est incorrect */
#define EX_MODETAT 20 /* l'etat interne du module est incorrect */
#define EX_MODERR 21 /* erreur specifique au module */
#define EX_NOTNUM 22 /* erreur de conversion de chaine en number */
#define EX_NOCLASS 23 /* la classe n'a pas ete trouvee dans la hash globale */
#define EX_CMDLINE_ARG 24 /* erreur dans les parametres de la ligne de commande */
#define EX_PCODE 25 /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
#define EX_NOENVVAR 26 /* WBIN et/ou WSRC non defini en var d'envvironnement ou non passe en parametre de la ligne de commande */
#define EX_EXCEPTNUM 27 /* code except ne tient pas sur 8 bits : ko pour retour shell */
#define EX_BINVAR_KO 28 /* variable _bin de g non trouvee */
#define EX_ENVVAR_KO 29 /* variable _env de g non trouvee */
#define EX_BINADDRVAR_KO 30 /* variable _binaddr de g non trouvee */
#define EX_CREATEHASH 31 /* erreur de creation de hashtable (memoire) */
#define EX_FIELD_KO 32 /* erreur lors de dynField (memoire ou param incorrect) */
#define EX_SUBSTR_KO 33 /* erreur lors de dynSubstr (memoire ou param incorrect) */
#define EX_SEP_INCORRECT 34 /* separateurs incorrects dans setsep (0 interdit) */
#define EX_FORMAT_KO 35 /* erreur de parametre (type format ou longueur incorrects) */
#define EX_INSERT_KO 36 /* erreur de parametre ou memoire dans insert() */
#define EX_REMOVE_KO 37 /* erreur de parametre ou memoire dans remove() */
enum {
OK = 0,
EX_DIV0 = 1, /* exceptions */
EX_MEM = 2, /* memalloc ko */
EX_BUFOVF = 3, /* depassement de capacite du buffer */
EX_IO = 4,/* erreur d'entree/sortie (leture fichier...) */
EX_END = 5, /* adresse du code hors prog/sub */
EX_LGNOM = 6, /* lg nom variable incorrecte (de 1 a 24 inclus) */
EX_TYPVAR = 7, /* type variable non attendu */
EX_NULLOCAL = 8, /* hashtable locale null et pas dans le code "global" */
EX_NOVAR = 9, /* nom de variable inconnu */
EX_MODOPEN = 10, /* erreur ouverture module (dlopen) */
EX_MODDSYM = 11, /* fonction execModule non trouvee dans le module (dsym) */
EX_NOSTACK = 12, /* dans ENDS, pas de var _stack trouve pour revenir a l'appelant */
EX_NAVAR = 13, /* la variable n'est pas du bon type / not available */
EX_NOADVAR = 14, /* pointeur ad_var non renseigne pour l'instruction qui en a besoin */
EX_NAVERS = 15, /* version de pcode non prise en charge par le "compilateur" */
EX_MODNAME = 16, /* le nom d'appel du module est incorrect */
EX_DYNERR = 17, /* erreur dans la manipulation des chaines */
EX_MODFUNC = 18, /* le code function du module est inconnu */
EX_MODPARAM = 19, /* le parametre donne au module est incorrect */
EX_MODETAT = 20, /* l'etat interne du module est incorrect */
EX_MODERR = 21, /* erreur specifique au module */
EX_NOTNUM = 22, /* erreur de conversion de chaine en number */
EX_NOCLASS = 23, /* la classe n'a pas ete trouvee dans la hash globale */
EX_CMDLINE_ARG = 24, /* erreur dans les parametres de la ligne de commande */
EX_PCODE = 25, /* pcode "binaire" incorrect : ne commence pas par PROG, library ne commence pas par LIBR, etc.*/
EX_NOENVVAR = 26, /* WBIN et/ou WSRC non defini en var d'environnement ou non passe en parametre de la ligne de commande */
EX_EXCEPTNUM = 27, /* code except ne tient pas sur 8 bits : ko pour retour shell */
EX_BINVAR_KO = 28, /* variable _bin de g non trouvee */
EX_ENVVAR_KO = 29, /* variable _env de g non trouvee */
EX_BINADDRVAR_KO = 30, /* variable _binaddr de g non trouvee */
EX_CREATEHASH = 31, /* erreur de creation de hashtable (memoire) */
EX_FIELD_KO = 32, /* erreur lors de dynField (memoire ou param incorrect) */
EX_SUBSTR_KO = 33, /* erreur lors de dynSubstr (memoire ou param incorrect) */
EX_SEP_INCORRECT = 34, /* separateurs incorrects dans setsep (0 interdit) */
EX_FORMAT_KO = 35, /* erreur de parametre (type format ou longueur incorrects) */
EX_INSERT_KO = 36, /* erreur de parametre ou memoire dans insert() */
EX_REMOVE_KO = 37, /* erreur de parametre ou memoire dans remove() */
EX_CHILD_FORK = 38, /* erreur de fork sur nouveau process */
EX_CHILD_EXEC = 39, /* erreur execution nouveau process */
EX_ZERO_FOR_INCR = 40, /* erreur increment a zero dans une boucle foreach numerique */
EX_SORTEDSEARCH_KO = 41, /* erreur de parametre (type de tri incorrect) */
EX_SQRT_NEG = 42, /* racine carre d'un nombre negatif non calculee */
EX_INT_EXP = 43, /* exponentiation fractionnaire non calculee */
EX_VARPARAM_KO = 44, /* la variable passee en parametre n'est plus presente en memoire */
EXNB = 44 /* MEMO !!!! */
};
typedef struct {
/* environnement global */
@@ -250,8 +274,9 @@ typedef struct {
octet tmp_cpt; /* nb de var tmp Dynamic, ne pas sauvegarder car dans la hash globale */
octet tmp_free; /* numero de var tmp Dynamic dispo ; si > tmp_cpt, a creer dans la hash globale */
//
//var tblptr; /* contient les pointeurs sur les vars de type SUB/PARAM/OBJET, pour les rendre VAR_NULL si le ptr est libere */
var varptrtbl; /* contient les pointeurs sur les vars de type SUB/PARAM/OBJET, pour les rendre VAR_NULL si le ptr est libere */
//
var tmp_dynamic; /* comme son nom l'indique... doit etre utilise localement et sur une portee tres courte ; pas d'utilisation inter instruction */
var int_number; /* variable number interne servant aux conversions */
var int_dynamic; /* variable dynamic interne servant aux conversions */
var int_hash; /* variable interne servant a la creation de classe/objet */
@@ -259,6 +284,9 @@ typedef struct {
var v; /* variable servant en interne */
var * ad_var; /* permet de recuperer l'adresse d'une var entre 2 instructions */
var * ad_var_hash; /* dans les enchainements PVAR/PVAH-PVAI, donne l'adresse de la hash possédant la "derniere" variable */
var * ad_var_obj; /* dans une affectation let ou do sub, donne l'objet concerne si objet, pour lire les membres (hors sub) -> pour creer this */
var * ad_var_class; /* donne l'objet de la classe mere de l'objet courant, objet Base si objet de classe Base */
var * ad_var_sav; /* pour memoriser ad_var sur une affectation simple let a.b = c.d, instruction SADV / VLET / PHDV / PIDV */
/* */
ent64 exception; /* exception courante (di) ; 0 ok, si # 0, levee d'une exception et saut au code qui le traite, 0 a chaque debut de fonction */
ent64 except_ex; /* dans bloc except, code erreur ayant genere l'exception ; a mettre a 0 a chaque debut de methode sauf si appel depuis le bloc except ! */
@@ -275,6 +303,8 @@ typedef struct {
var debugreglelex;
var debugcmd;
var debugvalex;
var printf;
void * debugCtxShm; /* pour le debug des process phantom */
/* */
octet bin_comp; /* indique si les binaires lus sont compresses (1) et si oui, avec une cle (2), 0 RAS */
octet demon; /* 1 si prog lance en demon, 0 sinon (lu par @demon) */
@@ -289,28 +319,38 @@ typedef struct {
char sep_field, sep_subfield; /* pour dynamic */
/* */
int endianess; /* pour detection automatique de l'endianess de la plateforme d'execution */
int use_signal; /* 1 si w gere et traite les signaux, 0 sinon (mode plugin : signaux geres par programme maitre) */
/* */
int level; /* niveau d'imvrication des appels do/call ; prog principal = level 1 */
/* */
int bin_indice; /* position dans _bin du binaire en cours d'exec ( _bin<2, bin_indice> ) */
/* */
pointeur debut,fin; /* position en memoire de la fonction, fin est toujours l'instruction END ou ENDS */
pointeur si; /* position dans le source, inclus entre debut et fin inclus */
pointeur si_except; /* position dans le source du code traitant les exceptions (apres instruction EXC) */
pointeur debutProg, finProg; // debut:fin du prog principal (= toute la zone memoire du prog)
/* */
pointeur binaddr; /* permet de lire les adresses binaires en mode Trace */
/* */
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 */
/* */
/* table des caracteres de '000' a '999' (pour conversion) */
char tbl_1000[3000];
@@ -318,18 +358,47 @@ typedef struct {
char var_car[VAR_NB + 1]; /* lettre caracteristique de chaque type (printdebug) */
} env;
#define CMP_EQ 1
#define CMP_NE 2
#define CMP_LT 3
#define CMP_GT 4
#define CMP_LE 5
#define CMP_GE 6
enum {
CMP_EQ = 1,
CMP_NE = 2,
CMP_LT = 3,
CMP_GT = 4,
CMP_LE = 5,
CMP_GE = 6,
CMP_AND = 7,
CMP_OR = 8,
CMP_NOT = 9,
CMP_FOR = 10
};
#define CMP_AND 7
#define CMP_OR 8
#define CMP_NOT 9
enum {
FORMAT_TRIM = 1,
FORMAT_LEFT = 2,
FORMAT_RIGHT = 3,
FORMAT_CENTER = 4,
FORMAT_SURROUND = 5
};
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@forcount,@kill,@fork,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@number,@dynamic,@empty,@trim,@left,@right,@center,@surround;1,2,3,4,5,6,7,8,10,11,12,13,14,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,40,41,42,50,51,52,53,54"
enum {
SORTEDSEARCH_NONE = 0,
SORTEDSEARCH_ASC = 1, // = DYN_SORT_ASC
SORTEDSEARCH_DESC = 2 // = DYN_SORT_DESC
};
#define GUV_CLASS "_class"
#define GUV_BINADDR "_binaddr"
#define GUV_LOCAL "_local"
#define GUV_ENV "_env"
#define GUV_ARG "_arg"
#define GUV_WARGV "_wargv"
#define GUV_ARGBACK "_argback"
#define GUV_SRCDBG "_srcdbg"
#define GUV_PROG "_prog"
#define GUV_STACK "_stack"
#define GUV_BIN "_bin"
#define GUV_WDIR "_wdir"
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@level,@kill,@oid,@prog,@exceptstr,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@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"
+339 -32
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -47,42 +47,254 @@ reste: (1,1,#00-#FF) ;11; 1,1,00-FF
[] est remplace par () car cela revient au meme !
*/
long regles_lex(env * e, Dynamic * r)
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
static struct {
long blanc, nomregle, debut, fin, occ, infini, commentaire, intervalle, hexa, car, reste;
} rlex;
static long rg_lex(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
{
dynLet(e, r, "", 0);
dynConcatSz(e, r, "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11\n", DYN_LGNONE);
//printf("%s", r->mPtr);
dynConcatSz(e, r, "1,-1,20:09\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,28\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,29\n", DYN_LGNONE);
dynConcatSz(e, r, "1,9,30-39;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2A;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,3B;0,-1,09-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2D\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,23;2,2,30-39:41-46\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,21-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,00-FF", DYN_LGNONE);
return DYN_OK;
// renvoie le numero de la regle a partir de son nom, 0 si non trouvee ou erreur conversion en numerique
long pos = dynLocateSz(e, regles, nom, ',', 1, 10);
if(pos > 0)
{
dynField(e, regles, tmp, 1, pos + 1, 10, ',', 1);
pos = dynToNum(e, tmp, DYN_FALSE, 5); // pas de signe et num regle sur 16 bits : 5 chiffres
if(tmp->mInternal != DYN_OK)
pos = 0;
}
return pos;
}
//
long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
WAPIDECL void init_reg_lex(env * e, Dynamic * regles, Dynamic * tmp)
{
long cr;
rlex.blanc = rg_lex(e, regles, "blanc", tmp); // 1
rlex.nomregle = rg_lex(e, regles, "nomregle", tmp); // 2
rlex.debut = rg_lex(e, regles, "debut", tmp); // 3
rlex.fin = rg_lex(e, regles, "fin", tmp); // 4
rlex.occ = rg_lex(e, regles, "occ", tmp); // 5
rlex.infini = rg_lex(e, regles, "infini", tmp); // 6
rlex.commentaire = rg_lex(e, regles, "commentaire", tmp); // 7
rlex.intervalle = rg_lex(e, regles, "intervalle", tmp); // 8
rlex.hexa = rg_lex(e, regles, "hexa", tmp); // 9
rlex.car = rg_lex(e, regles, "car", tmp); // 10
rlex.reste = rg_lex(e, regles, "reste", tmp); // 11
}
WAPIDECL long parse_lex(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic * trav, Dynamic * encours, int runtime)
{
#define nreg(x) ((x)*2 > trav->mLg ? 0 : *(ent16 *)(trav->mPtr + (x)*2 - 2))
/* */
static int numlig = 0;
numlig++;
/* */
if(valex->mLg == 0)
return OK; /* ligne vide */
/* */
int nbres = dynDcount(e, resultat, 10, DYN_NONE, DYN_NONE);
int nbval = dynDcount(e, valex, cVM, 2, cFM);
ent16 regle;
dynSetLen(e, trav, 0);
dynSetLen(e, encours, 0);
for(int ival = nbval; ival > 0; ival--)
{
/* suppression des regles 1 et 7 (blanc et commentaire) */
dynField(e, valex, tmp, 2, ival, cFM, cVM, 1);
regle = dynToNum(e, tmp, DYN_FALSE, 0);
if(regle == rlex.blanc || regle == rlex.commentaire)
{
dynDel(e, valex, 1, ival, cFM, cVM, 1);
dynDel(e, valex, 2, ival, cFM, cVM, 1);
dynDel(e, valex, 3, ival, cFM, cVM, 1);
}
else
{
if(dynCtrl(e, trav, trav->mLg + 2, TRUE) != DYN_OK)
return DYN_ERR;
if(trav->mLg > 0)
memcopie(trav->mPtr + 2, trav->mPtr, trav->mLg);
*(ent16 *)(trav->mPtr) = regle;
dynSetLen(e, trav, trav->mLg + 2);
}
}
//dynDel(e, valex, 2, DYN_NONE, cFM, DYN_NONE, 1);
if(trav->mLg == 0)
return OK; /* blancs et/ou commentaire seuls */
/* */
//for(int i=1;i<=trav->mLg/2;i++) printf("%d,",nreg(i)); printf("\n");
/* debut d'analyse des tokens : nomregle */
if(nreg(1) != rlex.nomregle)
{
dynField(e, valex, tmp, 3, 1, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : nom regle attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_RULENAME_EXPECTED;
}
/* liste de et/ou */
for(ent16 n = 2;;)
{
if((regle = nreg(n)) == 0)
break;
/* */
if(regle == rlex.debut || regle == rlex.car) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : car ou debut et/ou attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_CHAR_BRACKET_EXPECTED;
}
/* et */
if(n == 2)
dynStoreSz(e, valex, 4, DYN_NONE, "", 0, cFM, DYN_NONE);
else
dynConcatSz(e, valex, ";", 1);
/* */
if(regle == rlex.car)
{
/* 1 caractere = (1,1,car) (raccourci d'ecriture) */
dynConcatSz(e, valex, "1,1,", 4);
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(e, valex, tmp);
n++;
continue;
}
if(nreg(n+1) == rlex.occ && (nreg(n+2) == rlex.occ || nreg(n+2) == rlex.infini)) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : occurence min/max attendue %d\n", numlig, tmp->mPtr, n);
return EXMOD_COMPILE_OCCURENCE_EXPECTED;
}
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
dynConcat(e, valex, encours); // occmin
n++;
if(nreg(n) == rlex.infini)
dynConcatSz(e, valex, "-1,", 3);
else
{
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
dynConcat(e, valex, encours); // occmax
}
ent16 n1,n2,n3; char unefois[2] = {0};
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
while(n1 == rlex.car || n1 == rlex.hexa || ((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa)))
{
dynConcatSz(e, valex, unefois, DYN_LGNONE);
if((n1 == rlex.car || n1 == rlex.hexa) && n2 == rlex.intervalle && (n3 == rlex.car || n3 == rlex.hexa))
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
if(n1 == 10)
dynConcat(e, valex, tmp);
else
{
hex2str(e, tmp, encours);
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
dynConcatSz(e, valex, "-", 1);
n += 2;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
if(n3 == rlex.car)
dynConcat(e, valex, tmp);
else
{
hex2str(e, tmp, encours);
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
}
else if(n1 == rlex.car)
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
dynConcat(e, valex, tmp);
}
else if(n1 == rlex.hexa)
{
n++;
dynField(e, valex, tmp, 1, n, cFM, cVM, 1);
hex2str(e, tmp, encours);
dynConcatSz(e, valex, encours->mPtr + 1, DYN_LGNONE); // copier apres le #
}
n1 = nreg(n+1);
n2 = nreg(n+2);
n3 = nreg(n+3);
unefois[0] = ':';
}
if(unefois[0] == 0)
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : caractere/intervalle attendu\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_CHAR_INTERVAL_EXPECTED;
}
if(n1 == rlex.fin) ; else
{
dynField(e, valex, tmp, 3, n, cFM, cVM, 1);
if(!runtime) printf("Erreur ligne %dc%s : fin et/ou attendue\n", numlig, tmp->mPtr);
return EXMOD_COMPILE_BRACKET_EXPECTED;
}
n += 2;
}
/* lecture nom regle en hexa */
dynField(e, valex, tmp, 1, 1, cFM, cVM, 1);
hex2str(e, tmp, trav);
trav->mPtr[trav->mLg - 1] = ','; /* exemple : begin,1,comment,2,... permet de faire un locate */
dynConcatSz(e, trav, Int64ToSz(e, nbres == 0 ? 1 : nbres, DYN_FALSE, 0), DYN_LGNONE);
dynStore(e, resultat, 1, nbres == 0 ? 1 : nbres*2-1, trav, 10, ',');
/* */
dynField(e, valex, tmp, 4, DYN_NONE, cFM, DYN_NONE, 1);
nbres = (nbres == 0 ? 2 : nbres + 1);
dynStoreSz(e, resultat, nbres, DYN_NONE, tmp->mPtr, tmp->mLg, 10, DYN_NONE);
/* */
#undef nreg
return OK;
}
#include "lex_files.h"
WAPIDECL long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
long cr = DYN_ERR;
if(fichier_lex != NULL)
cr = dynRead(e, regles, fichier_lex); // lire les regles depuis le fichier sur disque
else
cr = regles_lex(e, regles); // par defaut, charger les regles lex des fichiers "lex"
//
if(cr == DYN_OK)
{
dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
//dynDel(e, regles, 1, DYN_NONE, 10, DYN_NONE, 1); /* la premiere ligne contient le <numero,nom> des regles, separe par "," */
/* selon fichier_lex, lire directement depuis le source */
if(strncmp(fichier_lex, "debuglex", 8) == 0)
{
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "wlex", 4) == 0)
{
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "lexlex", 6) == 0)
{
cr = dynLet(e, regles, file_lexlex, DYN_LGNONE);
}
}
//dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
return cr;
}
//
long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
static long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
{
long conc = 1, lgconc = 0, fin = FALSE, ichaine = 0, nch, t1, t2, trouve;
long occmin, occmax, occtrouve, occsuiv;
@@ -181,8 +393,8 @@ long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dyna
conc = lgconc;
return conc;
}
//
void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
WAPIDECL void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
{
/* vars Dynamic :
regles (en entree) : liste des regles ; etregle : regle ET en cours
@@ -334,7 +546,102 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynFree(e, &motencours);
dynFree(e, &trouvemot);
}
/* source Universe (OK) :
WAPIDECL long compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile)
{
// "compile" les regles lex fournies dans <fichier_lex> et renvoi le resultat dans <compile>
// <1> = nom et numeros des regles, <2> a <n> = regles lex
long cr = DYN_OK, ret = 0;
Dynamic regles, tmp, ligne, tmp1, tmp2, tmp3;
//
dynInit(e, &regles, 0);
dynInit(e, &tmp, 0);
dynInit(e, &ligne, 0);
dynInit(e, &tmp1, 0);
dynInit(e, &tmp2, 0);
dynInit(e, &tmp3, 0);
//
dynSetLen(e, compile, 0);
//
cr = lire_regles_lex(e, &regles, "lexlex"); // <regles> = regles lex compiles
if(cr == DYN_OK)
{
init_reg_lex(e, &regles, &tmp);
dynErase(e, fichier_lex, "\r");
dynRemove(e, fichier_lex, NULL, 0, DYN_TRUE);
while(dynRemove(e, fichier_lex, &ligne, 10, DYN_FALSE) > -1 && ret == 0)
{
lex(e, &regles, &ligne, &tmp); // tmp au format "valex" : chaine/noregle/position
ret = parse_lex(e, &tmp, compile, &tmp1, &tmp2, &tmp3, 1); /* 1 = runtime on (appel depuis lexMod), pas de printf */
}
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\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", 14, 10, DYN_NONE);
dynConcatSz(e, compile, "\n1,1,00-FF", 10);
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 = ""
* 1 entete
+46
View File
@@ -0,0 +1,46 @@
/* **********************************************
__ __ __
\ \/ \/ / 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
#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 compile_lex(env * e, Dynamic * fichier_lex, Dynamic * compile);
WAPIDECL long compile_like(env * e, Dynamic * like, Dynamic * compile);
#endif
+13
View File
@@ -0,0 +1,13 @@
; fichier de description du lex des fichiers lex
blanc: (1,*,#20#09) ;1; 1,-1,20:09
nomregle: (1,1,a-z) (0,*,0-9a-z) (1,1,#3A) ;2; 1,1,61-7A;0,-1,30-39:61-7A;1,1,3A
debut: (1,1,#28) ;3; 1,1,28
fin: (1,1,#29) ;4; 1,1,29
occ: (1,9,0-9) (1,1,#2C) ;5; 1,9,30-39;1,1,2C
infini: (1,1,#2A) (1,1,#2C) ;6; 1,1,2A;1,1,2C
commentaire: (1,1,#3B) (0,*,#20-#7E) ;7; 1,1,3B;0,-1,20-7E
intervalle: (1,1,#2D) ;8; 1,1,2D
hexa: (1,1,#23) (2,2,0-9A-F) ;9; 1,1,23;2,2,30-39:41-46
car: (1,1,#21-#7E) ;10; 1,1,21-7E
reste: (1,1,#00-#FF) ;11; 1,1,00-FF
+218
View File
@@ -0,0 +1,218 @@
/* **********************************************
__ __ __
\ \/ \/ / 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;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
//
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(modFnIs(e, "compile", 7))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, compile_lex(e, param1, param2));
if(exc == OK && param3 != NULL)
if(param3->type == VAR_HASHTABLE)
{
var * v = &e->int_number;
hashtable_clear(e, param3);
long cpt, nb = dynDcount(e, param2, ',', 1, 10);
for(cpt = 1; cpt < nb;)
{
dynField(e, param2, &e->tmp_dynamic, 1, cpt++, 10, ',', 1);
e->int_number.num = dynFieldAsNumber(e, param2, 1, cpt++, 10, ',') * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, e->tmp_dynamic.mPtr), &v);
}
}
}
}
/* ============================================================================================= */
else if(modFnIs(e, "analyze", 7))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC) // rules - input - result
exc = EX_MODPARAM;
else
{
lex(e, param1, param2, param3);
}
}
/* ============================================================================================= */
else if(modFnIs(e, "getToken", 8))
{
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC) // liste token trouves
exc = EX_MODPARAM;
else if(param2->type != VAR_NUMBER && param2->type != VAR_DYNAMIC) // indice
exc = EX_MODPARAM;
else if(param3->type != VAR_HASHTABLE) // hashtable contenant les 3 resultats : valeur (clair), no regle et position dans la source (input de analyze)
exc = EX_MODPARAM;
else
{
/* ne pas vider la hash, juste ecrire 3 elements : ruleValue, ruleNumber, ruleLocation */
number indice;
if( ! var_conv_num(e, param2, &indice))
exc = EX_MODPARAM;
else
{
indice /= NUM_FACTEUR;
var * n = &e->int_number;
n->num = dynExtractSubFieldAsNumber(e, param1, 2, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, "ruleNumber"), &n);
/* */
var * v = &e->int_dynamic, * w = &e->tmp_dynamic;
if(n->num == 0)
dynSetLen(e, v, 0);
else
{
dynExtractSubField(e, param1, 1, indice, w);
hex2str(e, w, v);
}
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, "ruleValue"), &v);
/* */
if(n->num != 0)
n->num = dynExtractSubFieldAsNumber(e, param1, 3, indice, NULL) * NUM_FACTEUR;
hashtable_do(e, HASH_WRITE, param3, copy_nom(e, "ruleLocation"), &n);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
+46
View File
@@ -0,0 +1,46 @@
// !! ne pas mettre de caracteres \r dans les constantes ci-dessous !!
// fichiers lex
static char file_lexlex[] = "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11\n"
"1,-1,20:09\n"
"1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n"
"1,1,28\n"
"1,1,29\n"
"1,9,30-39;1,1,2C\n"
"1,1,2A;1,1,2C\n"
"1,1,3B;0,-1,09-7E\n"
"1,1,2D\n"
"1,1,23;2,2,30-39:41-46\n"
"1,1,21-7E\n"
"1,1,00-FF";
// debugger w
static char file_debuglex[] = "blanc,1,commande,2,aide,3,nombre,4,ajouter,5,supprimer,6,ident,7,identnext,8,reste,9\n"
"1,-1,20:09:0A:0D\n"
"1,2,61-7A:41-5A\n"
"1,1,3F\n"
"1,9,30-39\n"
"1,1,2B\n"
"1,1,2D\n"
"1,1,3A;1,1,61-7A:41-5A:5F;0,23,61-7A:41-5A:30-39\n"
"1,1,2E;1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n"
"1,1,00-FF";
// langage W
/*static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,"
"continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,sortedsearch,60,"
"change,61,format,62,insert,63,remove,64,tonum,65,tostring,66,equal,67,diff,68,gt,69,lt,70,gte,71,lte,72,and,73,or,74,not,75,beginpar,76,endpar,77,beginh,78,endh,79,begins,80,ends,81,indirect,82,typeof,83,stringdq,84,stringq,85,ident,86,varsys,87,numberdec,88,numberint,89,minus,90,"
"plus,91,multiply,92,divide,93,divident,94,modulo,95,concat,96,listesep,97,identsep,98,modsep,99,other,100"
"\n1,-1,20:09\n1,1,3B;0,-1,00-FF\n1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n1,1,65;1,1,6E;1,1,64\n1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n"
"1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n1,1,73;1,1,75;1,1,62\n1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n1,1,69;1,1,66\n1,1,74;1,1,68;1,1,65;1,1,6E\n1,1,65;1,1,6C;1,1,73;1,1,65\n1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n"
"1,1,64;1,1,6F\n1,1,63;1,1,61;1,1,6C;1,1,6C\n1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n"
"1,1,69;1,1,6E\n1,1,6C;1,1,69;1,1,6B;1,1,65\n1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n"
"1,1,6E;1,1,6F;1,1,70\n1,1,70;1,1,61;1,1,72;1,1,74\n1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n1,1,65;1,1,63;1,1,68;1,1,6F\n1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n1,1,6C;1,1,65;1,1,74\n1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n1,1,6E;1,1,65;1,1,77\n1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n"
"1,1,74;1,1,68;1,1,69;1,1,73\n1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n1,1,68;1,1,6F;1,1,6C;1,1,64\n1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n1,1,69;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,61;1,1,63\n1,1,61;1,1,62;1,1,73\n1,1,6E;1,1,65;1,1,67\n1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n"
"1,1,74;1,1,79;1,1,70;1,1,65\n1,1,6C;1,1,65;1,1,6E\n1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n"
"1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n1,1,3D\n1,1,23\n1,1,3E\n1,1,3C\n1,1,3E;1,1,3D\n1,1,3C;1,1,3D\n"
"1,1,61;1,1,6E;1,1,64\n1,1,6F;1,1,72\n1,1,6E;1,1,6F;1,1,74\n1,1,28\n1,1,29\n1,1,7B\n1,1,7D\n1,1,5B\n1,1,5D\n1,1,21\n1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66\n1,1,22;0,765,20-21:23-EF;1,1,22\n1,1,27;0,765,20-26:28-EF;1,1,27\n1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,40;1,-1,61-7A\n1,13,30-39;1,1,2E;0,5,30-39\n1,13,30-39\n1,1,2D\n"
"1,1,2B\n1,1,2A\n1,1,2F\n1,1,5C\n1,1,25\n1,1,3A\n1,1,2C\n1,1,2E\n1,1,26\n1,1,00-FF";
*/
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";
+55
View File
@@ -0,0 +1,55 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
/*
tester avec alloc (size 20) !! TODO
*/
enum {
MAX_ENTRY = 3838, // 4096 - 258
SIZE_ENTRY = (124 + sizeof(int)) // TODO : voir la meilleure taille 91 sur fichier binaire de 130 Ko... !!! tester avec 20...
};
typedef struct {
octet Dict[MAX_ENTRY * SIZE_ENTRY]; // dictionnaire en cours
int posDict; // prochaine entree a ecrire dans le dictionnaire
pointeur Alloc[MAX_ENTRY]; // pointeurs des blocs alloues en dehors des entry (car trop grand)
int allocEntry; // nb blocs alloue en dehors des entry (car trop grand)
var code; // de type dynamic, contient le code/decode en cours
var w; // de type dynamic, contient la chaine en cours d'analyse
long prec; // dernier code trouve dans le dict
long bits; // nb de bits en cours (codage/decodage)
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal)
int inverse; // "inverse" le decodage des bits LZW (cas des fichiers GIF)
} modContextLzw;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WAPIDECL void initLzw(env * e, modContextLzw * cl);
WAPIDECL void freeLzw(env * e, modContextLzw * cl);
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type);
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type);
+65 -300
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -27,17 +27,14 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "lzw.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
var dict; // de type dynamic, dictionnaire en cours
var code; // de type dynamic, contient le code/decode en cours
var w; // de type dynamic, contient la chaine en cours d'analyse
long prec; // dernier code trouve dans le dict
long posDict;// position en cours du code dans dict + 256 (dernier)
long bits; // nb de bits en cours (codage/decodage)
long reste; // bits restant a traiter lors du decodage (nb bits dans pe->code.mInternal)
modContextLzw cl;
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
@@ -51,32 +48,35 @@ static int setError(modEtat * p, int err)
return err == OK ? OK : EX_MODERR;
}
long set(env * e, var * clair, modEtat * pe, int type);
long get(env * e, var * code, modEtat * pe, int type);
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
/* */
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
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));
@@ -87,84 +87,89 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
dynInit(e, &p_etat->dict, 4096);
dynInit(e, &p_etat->code, 4096);
dynInit(e, &p_etat->w, 256);
initLzw(e, &p_etat->cl);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
freeLzw(e, &p_etat->cl);
//*** FIN du code specifique ici
memfree(e, p_etat);
//*** code specifique ici
dynFree(e, &p_etat->dict);
dynFree(e, &p_etat->code);
dynFree(e, &p_etat->w);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "set", 3))
{
/* compression du clair de param, en une fois */
/* sinon utiliser : setinit, setnext, setend */
/*exc = setError(p_etat, EXMOD_xxx);*/
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, set(e, param, p_etat, 0)); /* 0 : en une fois */
}
exc = setError(p_etat, setLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
}
/* ============================================================================================= */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
/* decompression du code de param, en une fois */
/* sinon utiliser getinit, getnext, getend */
/*exc = setError(p_etat, EXMOD_xxx);*/
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(param->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
exc = setError(p_etat, get(e, param, p_etat, 0)); /* 0 : en une fois */
p_etat->cl.inverse = FALSE;
if(param2 != NULL)
{
if(param2->type == VAR_DYNAMIC || param2->type == VAR_NUMBER)
{
number inv;
if(var_conv_num(e, param2, &inv))
p_etat->cl.inverse = (inv != 0 ? TRUE : FALSE);
}
}
exc = setError(p_etat, getLzw(e, param1, &p_etat->cl, 0)); /* 0 : en une fois */
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "xxx", 3) == 0)
{
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
exc = setError(p_etat, EXMOD_xxx);
}
/* ----------------------------------------------------------------------------------------------- */
else
{
@@ -174,243 +179,3 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
return exc;
}
/* **************************************************************************************************** */
void ecrireCode(env * e, modEtat * pe, long num)
{
long b = pe->bits; /* nb bits a ecrire */
/* ecrire dans pe->code le numero num selon pe->bits (9 10 11 12) */
/* il y a entre 1 et 3 octets a ecrire dans pe->code */
if(pe->code.mInternal > 0)
{
/* finir de remplir le dernier octet de pe->code : de 1 a 7 bits */
b -= pe->code.mInternal;
pe->code.ptr[pe->code.mLg - 1] |= (num >> b); /* il reste b bits a ecrire maintenant */
}
dynCtrl(e, &pe->code, pe->code.mLg + (b > 8 ? 2 : 1), 1); /* tester code retour ? */
if(b > 7)
{
/* ecrire un octet complet */
b -= 8;
pe->code.ptr[pe->code.mLg++] = (b ? (num >> b) : num) & 255;
}
if(b > 0)
{
/* ajouter les derniers bits */
b = 8 - b;
pe->code.ptr[pe->code.mLg++] = (num << b) & 255;
}
pe->code.mInternal = b; /* nb bits libres restant */
}
long set(env * e, var * clair, modEtat * pe, int type)
{
long pos;
/* codage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
dynSetLen(e, &pe->dict, 0);
dynSetLen(e, &pe->code, 0);
pe->code.mInternal = 0; /* nb de bits libres dans le dernier octet utilise de pe->code */
dynLet(e, &pe->w, sFM, 1); /* pour simplifier le concat plus loin */
pe->prec = -1;
pe->posDict = 258;
pe->bits = 9;
}
long lg_clair = clair->mLg;
unsigned char c;
char h[3] = {0}; /* c, en faux-hexa de a=0 jusqu'a p=15 (codes ascii 97 a 112) */
unsigned char * pclair = clair->ptr; /* ptr en unsigned */
while(lg_clair--)
{
c = *pclair++;
h[0] = (c / 16) + 97;
h[1] = (c % 16) + 97;
dynConcatSz(e, &pe->w, h, 2);
/* */
if(pe->w.mLg == 3)
{
/* code simple : trouve */
pe->prec = (long)c;
}
else if((pos = dynLocateSz(e, &pe->dict, pe->w.mPtr + 1, cFM, DYN_NONE, DYN_NONE)) > 0) /* ne pas chercher le FM en debut de w */
{
/* code compose trouve */
pe->prec = pos + 256;
}
else
{
/* pas trouve */
/* 1. ecriture de pe->prec dans pe->code */
ecrireCode(e, pe, pe->prec);
/* 2. ajout de w au dict */
dynConcat(e, &pe->dict, &pe->w);
/* 3. gestion changement bits */
if(pe->posDict == 511 || pe->posDict == 1023 || pe->posDict == 2047)
pe->bits++; /* passage a 10,11,12 bits */
if(pe->posDict == 4095)
{
/* 3.1 ecrire 256 (raz bits) */
ecrireCode(e, pe, 256);
/* 3.2 raz dict */
dynSetLen(e, &pe->dict, 0);
pe->posDict = 258;
pe->bits = 9;
}
else
pe->posDict++;
/* 4. w = c */
dynLet(e, &pe->w, sFM, 1);
dynConcatSz(e, &pe->w, h, 2);
pe->prec = (long)c;
}
}
if(type == 3 || type == 0)
{
/* ecrire pe->prec (dernier code en cours) */
if(pe->prec > -1)
ecrireCode(e, pe, pe->prec);
/* ecrire 257 */
ecrireCode(e, pe, 257);
/* copie du resultat dans le parametre en sortie */
dynLet(e, clair, pe->code.mPtr, pe->code.mLg);
}
/* */
return OK;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
long get(env * e, var * comp, modEtat * pe, int type)
{
long v; /* code en cours de decodage */
unsigned char * p;
long masque[8] = {0, 1, 3, 7, 15, 31, 63, 127};
/* decodage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
dynSetLen(e, &pe->dict, 0);
dynSetLen(e, &pe->code, 0);
pe->code.mInternal = 0; /* nb bits restant en entree, a traiter (contenu dans pe->reste) */
pe->reste = 0;
dynSetLen(e, &pe->w, 0);
pe->prec = -1;
pe->posDict = 258;
pe->bits = 9;
}
long lg_comp = comp->mLg, lg;
char h[3] = {0};
unsigned char c;
unsigned char * pcomp = comp->ptr; /* ptr en unsigned */
while(lg_comp--)
{
/* lire les bits pour trouver le prochain code */
c = *pcomp++;
/* */
pe->reste = (pe->reste << 8) | c;
pe->code.mInternal += 8;
if(pe->code.mInternal < pe->bits)
continue;
pe->code.mInternal -= pe->bits; /* maxi 7 bits restants */
if(pe->code.mInternal == 0)
v = pe->reste;
else
v = pe->reste >> pe->code.mInternal;
pe->reste &= masque[pe->code.mInternal];
/* */
if(v == 256)
{
/* raz dict */
dynSetLen(e, &pe->dict, 0);
pe->posDict = 258;
pe->bits = 9;
pe->prec = -1;
continue;
}
if(v == 257)
break;
/* v est-il dans le dictionnaire ? */
if(v < pe->posDict)
{
/* *** oui *** */
/* ecrire dans le clair (pe->code) le dict[v] */
if(v < 256)
{
dynCtrl(e, &pe->code, pe->code.mLg + 1, 1);
pe->code.ptr[pe->code.mLg++] = (unsigned char)v;
h[0] = (v / 16) + 97;
h[1] = (v % 16) + 97;
}
else
{
dynField(e, &pe->dict, &pe->w, v - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
/* garder en memoire le premier caractere du dict (h) */
h[0] = pe->w.mPtr[0];
h[1] = pe->w.mPtr[1];
dynSetLen(e, &pe->w, 2);
}
if(pe->prec != -1)
{
/* recup dict<pe->prec> dans w */
if(pe->prec < 256)
{
pe->w.ptr[0] = (pe->prec / 16) + 97;
pe->w.ptr[1] = (pe->prec % 16) + 97;
dynSetLen(e, &pe->w, 2);
}
else
dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* ajout premier car du dict<v> (h) */
dynConcatSz(e, &pe->w, h, 2);
/* ecrire le nouveau dict */
dynConcatSz(e, &pe->dict, sFM, 1);
dynConcat(e, &pe->dict, &pe->w);
pe->posDict++;
if(pe->posDict == 511 || pe->posDict == 1023 || pe->posDict == 2047)
pe->bits++; /* bug passage a 10,11,12 bits */
}
}
else
{
/* *** non *** */
/* recup dict<pe->prec> dans w (ici, pe->prec ne peut pas etre a -1) */
if(pe->prec < 256)
{
pe->w.ptr[0] = (pe->prec / 16) + 97;
pe->w.ptr[1] = (pe->prec % 16) + 97;
dynSetLen(e, &pe->w, 2);
}
else
dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* ajout premier car du dict<pe->prec> (w) a sa fin elle meme (w) */
h[0] = pe->w.mPtr[0];
h[1] = pe->w.mPtr[1];
dynConcatSz(e, &pe->w, h, 2);
/* ecrire w dans le clair, w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
/* ecrire le nouveau dict */
dynConcatSz(e, &pe->dict, sFM, 1);
dynConcat(e, &pe->dict, &pe->w);
pe->posDict++;
if(pe->posDict == 511 || pe->posDict == 1023 || pe->posDict == 2047)
pe->bits++; /* bug : passage a 10,11,12 bits */
}
pe->prec = v;
}
/* */
if(type == 3 || type == 0)
{
/* traiter les bits restant (y-en-a-t-il ?) => a priori, tout a deja ete traite avant... */
/* copie du resultat dans le parametre en sortie */
dynLet(e, comp, pe->code.mPtr, pe->code.mLg);
}
/* */
return OK;
}
+390
View File
@@ -0,0 +1,390 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "lzw.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
static void InitDict(env * e, modContextLzw * cl)
{
cl->posDict = 0; // prochaine entree
// pour chaque entree, liberer tout bloc alloue (quand lg < 0 de l'entree)
for(int alloc = 0; alloc < cl->allocEntry ; alloc++)
memfree(e, cl->Alloc[alloc]);
cl->allocEntry = 0;
}
static int SearchDictEntry(env * e, modContextLzw * cl, pointeur valeur, int lg)
{
// Dict => 0-255 : idem ; 256 : EOF ; 257 : RAZ nb bits ; 258-4095 : entrees
if(lg <= 1)
return *valeur;
pointeur pDict = cl->Dict;
for(int entry = 0; entry < cl->posDict; entry++, pDict += SIZE_ENTRY)
if(lg == *(int *)(pDict))
{
if(memcmp(valeur, pDict + sizeof(int), lg) == 0)
return entry + 258;
}
else if(-lg == *(int *)(pDict))
{
// bloc alloue en dehors de l'entry (trop grand)
if(memcmp(valeur, *(pointeur *)(pDict + sizeof(int)), lg) == 0)
return entry + 258;
}
return -1; // non trouve
}
static pointeur GetDictEntry(env * e, modContextLzw * cl, int entry, int * lg)
{
entry -= 258;
if(entry < 0 || entry >= cl->posDict)
return NULL;
pointeur pDict = cl->Dict + entry * SIZE_ENTRY;
if((*lg = *(int *)(pDict)) > 0)
return pDict + sizeof(int);
else
{
*lg = abs(*lg);
return *(pointeur *)(pDict + sizeof(int));
}
}
static int AddDictEntry(env * e, modContextLzw * cl, pointeur valeur, int lg)
{
if(cl->posDict < MAX_ENTRY && lg > 0)
{
if(lg <= SIZE_ENTRY - sizeof(int))
{
pointeur pDict = cl->Dict + cl->posDict * SIZE_ENTRY;
*(int *)pDict = lg;
memcpy(pDict + sizeof(int), valeur, lg);
cl->posDict++;
return 1; // TRUE : ok
}
else
{
// mettre la longueur en negatif et allouer un bloc de la bonne taille
pointeur alloc = memalloc(e, lg);
if(alloc)
{
cl->Alloc[cl->allocEntry++] = alloc;
//
pointeur pDict = cl->Dict + cl->posDict * SIZE_ENTRY;
*(int *)pDict = -lg;
*(pointeur *)(pDict + sizeof(int)) = alloc;
memcpy(alloc, valeur, lg);
cl->posDict++;
return 1;
}
else
return 0;
}
}
else
return 0;
}
static void ecrireCode(env * e, modContextLzw * cl, long num)
{
long b = cl->bits; /* nb bits a ecrire */
/* ecrire dans cl->code le numero num selon cl->bits (9 10 11 12) */
/* il y a entre 1 et 3 octets a ecrire dans cl->code */
if(cl->code.mInternal > 0)
{
/* finir de remplir le dernier octet de cl->code : de 1 a 7 bits */
b -= cl->code.mInternal;
cl->code.ptr[cl->code.mLg - 1] |= (num >> b); /* il reste b bits a ecrire maintenant */
}
dynCtrl(e, &cl->code, cl->code.mLg + (b > 8 ? 2 : 1), 1); /* tester code retour ? */
if(b > 7)
{
/* ecrire un octet complet */
b -= 8;
cl->code.ptr[cl->code.mLg++] = (b ? (num >> b) : num) & 255;
}
if(b > 0)
{
/* ajouter les derniers bits */
b = 8 - b;
cl->code.ptr[cl->code.mLg++] = (num << b) & 255;
}
cl->code.mInternal = b; /* nb bits libres restant */
}
/* ***** PUBLIC *************** */
WAPIDECL void initLzw(env * e, modContextLzw * cl)
{
cl->allocEntry = 0;
dynInit(e, &cl->code, 4096);
dynInit(e, &cl->w, 256);
}
WAPIDECL void freeLzw(env * e, modContextLzw * cl)
{
dynFree(e, &cl->code);
dynFree(e, &cl->w);
}
WAPIDECL long setLzw(env * e, var * clair, modContextLzw * cl, int type)
{
/* codage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
InitDict(e, cl);
dynSetLen(e, &cl->code, 0);
cl->code.mInternal = 0; /* nb de bits libres dans le dernier octet utilise de pe.le->code */
dynSetLen(e, &cl->w, 0);
cl->prec = -1;
cl->bits = 9;
}
long pos, lg_clair = clair->mLg;
unsigned char c[2], * pclair = clair->ptr; /* ptr en unsigned */
c[1] = 0;
while(lg_clair--)
{
c[0] = *pclair++;
dynConcatSz(e, &cl->w, (char *)c, 1);
/* */
if(cl->w.mLg == 1)
{
/* code simple : trouve */
cl->prec = c[0];
}
else if((pos = SearchDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg)) > -1)
{
/* code compose trouve */
cl->prec = pos;
}
else
{
/* pas trouve */
/* 1. ecriture de cl->prec dans cl->code */
ecrireCode(e, cl, cl->prec);
/* 2. ajout de w au dict */
AddDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg);
/* 3. gestion changement bits */
if(cl->posDict == 512 - 258 || cl->posDict == 1024 - 258 || cl->posDict == 2048 - 258)
cl->bits++; /* passage a 10,11,12 bits */
if(cl->posDict == 4096 - 258)
{
/* 3.1 ecrire 256 (raz bits) */
ecrireCode(e, cl, 256);
/* 3.2 raz dict */
InitDict(e, cl);
cl->bits = 9;
}
/* 4. w = c */
*cl->w.ptr = c[0];
dynSetLen(e, &cl->w, 1);
cl->prec = c[0];
}
}
if(type == 3 || type == 0)
{
/* ecrire cl->prec (dernier code en cours) */
if(cl->prec > -1)
ecrireCode(e, cl, cl->prec);
/* ecrire 257 */
ecrireCode(e, cl, 257);
/* copie du resultat dans le parametre en sortie */
dynLet(e, clair, cl->code.mPtr, cl->code.mLg);
InitDict(e, cl);
}
/* */
return OK;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - */
WAPIDECL long getLzw(env * e, var * comp, modContextLzw * cl, int type)
{
long v; /* code en cours de decodage */
long masque[13] = {0, 1, 3, 7, 15, 31, 63, 127, 0, 511, 1023, 2047, 4095}; // les 8 premiers servent au mode normal, les 4 derniers au mode "inverse"
/* decodage lzw, type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, type = 0 : un seul appel pour tout */
if(type == 1 || type == 0)
{
/* initialisations */
InitDict(e, cl);
dynSetLen(e, &cl->code, 0);
cl->code.mInternal = 0; /* nb bits restant en entree, a traiter (contenu dans cl->reste) */
cl->reste = 0;
dynSetLen(e, &cl->w, 0);
cl->prec = -1;
cl->bits = 9;
}
long lg_comp = comp->mLg;
int lg;
unsigned char c, h[2];
unsigned char * pcomp = comp->ptr; /* ptr en unsigned */
pointeur pEntry;
h[1] = 0;
while(lg_comp--)
{
/* lire les bits pour trouver le prochain code */
c = *pcomp++;
/* */
if(cl->inverse) // test, sinon param "inverse"
{
// cas LZW du giff (different de LZW natif/PDF !)
if(cl->code.mInternal == 0)
cl->reste |= c;
else
cl->reste |= (c << cl->code.mInternal);
cl->code.mInternal += 8;
if(cl->code.mInternal < cl->bits)
continue;
v = (cl->reste & masque[cl->bits]);
cl->reste >>= cl->bits;
cl->code.mInternal -= cl->bits;
}
else
{
cl->reste = (cl->reste << 8) | c;
cl->code.mInternal += 8;
if(cl->code.mInternal < cl->bits)
continue;
cl->code.mInternal -= cl->bits; /* maxi 7 bits restants */
if(cl->code.mInternal == 0)
v = cl->reste;
else
v = cl->reste >> cl->code.mInternal;
cl->reste &= masque[cl->code.mInternal];
}
/* */
if(v == 256)
{
/* raz dict */
InitDict(e, cl);
cl->bits = 9;
cl->prec = -1;
continue;
}
if(v == 257)
break;
/* v est-il dans le dictionnaire ? */
if(v - 258 < cl->posDict)
{
/* *** oui *** */
/* ecrire dans le clair (cl->code) le dict[v] */
if(v < 256)
{
h[0] = v;
dynConcatSz(e, &cl->code, (char *)h, 1);
}
else
{
pEntry = GetDictEntry(e, cl, v, &lg);
//dynField(e, &pe->dict, &pe->w, v - 256, DYN_NONE, cFM, DYN_NONE, 1);
/* w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
//dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
//for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
// pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
dynConcatSz(e, &cl->code, (char *)pEntry, lg);
/* garder en memoire le premier caractere du dict (h) */
h[0] = *pEntry;
*cl->w.mPtr = *pEntry; // utilite ? a mettre en commentaire
dynSetLen(e, &cl->w, 1); // utilite ? a mettre en commentaire
}
if(cl->prec != -1)
{
/* recup dict<cl->prec> dans w */
if(cl->prec < 256)
{
*cl->w.mPtr = cl->prec;
dynSetLen(e, &cl->w, 1);
}
else
{
//dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
pEntry = GetDictEntry(e, cl, cl->prec, &lg);
dynLet(e, &cl->w, (char *)pEntry, lg);
}
/* ajout premier car du dict<v> (h) */
dynConcatSz(e, &cl->w, (char *)h, 1);
/* ecrire le nouveau dict */
AddDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg);
//dynConcatSz(e, &pe->dict, sFM, 1);
//dynConcat(e, &pe->dict, &pe->w);
//cl->posDict++;
if(cl->posDict == 511 - 258 || cl->posDict == 1023 - 258 || cl->posDict == 2047 - 258)
cl->bits++;
}
}
else
{
/* *** non *** */
/* recup dict<cl->prec> dans w (ici, cl->prec ne peut pas etre a -1) */
if(cl->prec < 256)
{
*cl->w.mPtr = cl->prec;
dynSetLen(e, &cl->w, 1);
}
else
{
//dynField(e, &pe->dict, &pe->w, pe->prec - 256, DYN_NONE, cFM, DYN_NONE, 1);
pEntry = GetDictEntry(e, cl, cl->prec, &lg);
dynLet(e, &cl->w, (char *)pEntry, lg);
}
/* ajout premier car du dict<cl->prec> (w) a sa fin elle meme (w) */
h[0] = *cl->w.mPtr;
//h[1] = pe->w.mPtr[1];
dynConcatSz(e, &cl->w,(char *) h, 1);
/* ecrire w dans le clair, w contient le clair en faux-hexa : a=0 jusqu'a p=15 (codes ascii 97 a 112) */
//dynCtrl(e, &pe->code, pe->code.mLg + pe->w.mLg / 2, 1);
//for(p = pe->w.ptr, lg = pe->w.mLg; lg > 0; p += 2, lg -= 2)
// pe->code.ptr[pe->code.mLg++] = ((*p) << 4) + (*(p + 1)) - 1649; /* optimisation de : (*p - 97) * 16 + (*(p + 1)) - 97; */
dynConcatSz(e, &cl->code, cl->w.mPtr, cl->w.mLg);
/* ecrire le nouveau dict */
AddDictEntry(e, cl, (pointeur)cl->w.mPtr, cl->w.mLg);
//dynConcatSz(e, &pe->dict, sFM, 1);
//dynConcat(e, &pe->dict, &pe->w);
//cl->posDict++;
if(cl->posDict == 511 - 258 || cl->posDict == 1023 - 258 || cl->posDict == 2047 - 258)
cl->bits++;
}
cl->prec = v;
}
/* */
if(type == 3 || type == 0)
{
/* traiter les bits restant (y-en-a-t-il ?) => a priori, tout a deja ete traite avant... */
/* copie du resultat dans le parametre en sortie */
dynLet(e, comp, cl->code.mPtr, cl->code.mLg);
InitDict(e, cl);
}
/* */
return OK;
}
+11 -5
View File
@@ -44,6 +44,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#define WLIBDECL __declspec(dllexport)
#else
#define WLIBDECL
#endif
#ifndef UNIX
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
@@ -74,7 +80,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -88,7 +94,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
@@ -96,7 +102,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -111,7 +117,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -127,7 +133,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "xxx", 3) == 0)
else if(modFnIs(e, "xxx", 3))
{
//*** coder les autres fonctions ici de la meme maniere, au a mettre au debut !
exc = setError(p_etat, EXMOD_xxx);
+90
View File
@@ -0,0 +1,90 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "lzw.h"
/* ******* constantes ********** */
enum {
PDFFMT_A4P = 1, /* A4 portrait */
PDFFMT_A4L = 2, /* A4 paysage ("landscape") */
PDFFMT_A3P = 3, /* A3 portrait */
PDFFMT_A3L = 4, /* A3 paysage */
PDFFONT_COURIER = 1,
PDFFONT_COURIER_BOLD = 2,
PDFFONT_COURIER_BOLDOBLIQUE = 3,
PDFFONT_COURIER_OBLIQUE = 4,
PDFFONT_HELVETICA = 5,
PDFFONT_HELVETICA_BOLD = 6,
PDFFONT_HELVETICA_BOLDOBLIQUE = 7,
PDFFONT_HELVETICA_OBLIQUE = 8,
PDFFONT_TIMES_ROMAN = 9,
PDFFONT_TIMES_BOLD = 10,
PDFFONT_TIMES_ITALIC = 11,
PDFFONT_TIMES_BOLDITALIC = 12,
PDFFONT_SYMBOL = 13,
PDFFONT_ZAPFDINGBATS = 14,
PDFFONT_NB = 14
};
/* ***** MACRO ****/
#define RGB(r,g,b) (((((r&255)<<8)+(g&255))<<8)+(b&255))
typedef struct
{
Dynamic mPdf; /* PDF en cours de constitution */
Dynamic mPage; /* page en cours */
Dynamic mXref; /* liste des xref du PDF en cours (<1> contient le titre et les dimensions des images) */
Dynamic mImg; /* images en FM, en hexa, BMP 24/32 bpp uniquement (codage RGB) */
long mNbPage; /* nb de pages total du PDF */
long mFormat; /* A4 ou A3 et Paysage ou portrait */
long mLarg, mHaut; /* largeur/hauteur de la page en (mm x 10), selon le format */
long mNbObj; /* pour xref */
long mNumPage; /* numero page en cours */
long mLmarg; /* marge gauche en mm x 10 */
long mRmarg; /* marge droite en mm x 10 */
long mHmarg; /* marge haute en mm x 10 */
long mBmarg; /* marge basse en mm x 10 */
long mDimFont; /* taille fonte */
long mDimFontCadre;
long mDimLig;
Dynamic mFont; /* nom des 14 fontes standards */
modContextLzw mCtxLzw; /* gestion compression page lzw */
Dynamic mTmp1, mTmp2, mTmp3; /* temporaire pour le traitement */
} modContextPdf;
WAPIDECL void initPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL void freePdf(env * e, modContextPdf * ctxPdf);
WAPIDECL int newPdf(env * e, modContextPdf * ctxPdf, Dynamic * titre, long nb_page, long format, Dynamic * fonts);
WAPIDECL int endPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL Dynamic * getPdf(env * e, modContextPdf * ctxPdf);
WAPIDECL int setPdfPage(env * e, modContextPdf * ctxPdf, int compression);
WAPIDECL int setPdfText(env * e, modContextPdf * ctxPdf, long x, long y, long w, long h, long font, long taille, long couleur, Dynamic * txt);
WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, long y, long w, long h, long coul_trait, long coul_rempl, long epaisseur, long pointille);
WAPIDECL int setPdfImage(env * e, modContextPdf * ctxPdf, long x, long y, long img);
WAPIDECL int pdfDeleteImage(env * e, modContextPdf * ctxPdf, long img);
WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier);
WAPIDECL int pdfLoadImageGif(env * e, modContextPdf * ctxPdf, Dynamic * fichier);
WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic * lignes, long format);
+378
View File
@@ -0,0 +1,378 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "hashtable.h"
#include "pdf.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextPdf cp;
} modEtat;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
initPdf(e, &p_etat->cp);
}
}
else if(modFnIs(e, "end", 3))
{
if(p_etat != NULL)
{
//*** code specifique ici
freePdf(e, &p_etat->cp);
// fin liberation specifique module avant arret process
memfree(e, p_etat);
}
}
else if(modFnIs(e, "vers", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
else if(modFnIs(e, "beginDoc", 8))
{
// nouveau document pdf
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// lire les infos necessaires a la creation d'un nouveau doc. pdf :
// titre, nb pages, format, fontes utilisees
var * titre, * fontes, * nbPage, * format;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fontes"), &fontes);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Pages"), &nbPage);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Format"), &format);
if(titre && fontes && nbPage && format)
{
if(titre->type == VAR_DYNAMIC && fontes->type == VAR_DYNAMIC && nbPage->type == VAR_NUMBER && format->type == VAR_NUMBER)
{
number nnbPage, nformat;
if( var_conv_num(e, nbPage, &nnbPage) && var_conv_num(e, format, &nformat) )
exc = setError(p_etat, ! newPdf(e, &p_etat->cp, titre, nnbPage / NUM_FACTEUR, nformat / NUM_FACTEUR, fontes));
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "endDoc", 6))
{
// finalise le document pdf, et renvoi le contenu dans param1
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
int cr = endPdf(e, &p_etat->cp);
if(cr)
{
var_let(e, param1, getPdf(e, &p_etat->cp), FALSE, FALSE);
}
exc = setError(p_etat, ! cr);
}
}
/* ============================================================================================= */
else if(modFnIs(e, "addPage", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
// ajouter la page en cours au doucment pdf
exc = setError(p_etat, ! setPdfPage(e, &p_etat->cp, 1)); // 1 = avec compression ; parametrer ?
}
/* ============================================================================================= */
else if(modFnIs(e, "addText", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// ajouter le texte
var * x, * y, * w, * h; // cadre englobant
var * fonte, * taille, * couleur;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Fonte"), &fonte);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Taille"), &taille);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Couleur"), &couleur);
if(x && y && w && h && fonte && taille && couleur)
{
number nx, ny, nw, nh, nfonte, ntaille, ncouleur;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
var_conv_num(e, fonte, &nfonte) && var_conv_num(e, taille, &ntaille) && var_conv_num(e, couleur, &ncouleur) )
exc = setError(p_etat, ! setPdfText(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
nfonte / NUM_FACTEUR, ntaille / NUM_FACTEUR, ncouleur / NUM_FACTEUR, param2)); // param2 = texte
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "delImage", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER && param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number indice;
if(var_conv_num(e, param1, &indice))
exc = setError(p_etat, ! pdfDeleteImage(e, &p_etat->cp, indice / NUM_FACTEUR));
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "addGraph", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * w, * h; // cadre englobant
var * couleurTrait, * couleurRemplissage, * epaisseur, * pointille, * type;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "W"), &w);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "H"), &h);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CouleurTrait"), &couleurTrait);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "CouleurRemplissage"), &couleurRemplissage);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "EpaisseurTrait"), &epaisseur);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Pointille"), &pointille);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Type"), &type);
if(x && y && w && h && couleurTrait && couleurRemplissage && epaisseur && pointille && type)
{
number nx, ny, nw, nh, ntrait, nrempl, nepais, npoint;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, w, &nw) && var_conv_num(e, h, &nh) &&
type->type == VAR_DYNAMIC && var_conv_num(e, couleurTrait, &ntrait) && var_conv_num(e, couleurRemplissage, &nrempl) &&
var_conv_num(e, epaisseur, &nepais) && var_conv_num(e, pointille, &npoint) )
exc = setError(p_etat, ! setPdfGraph(e, &p_etat->cp, *type->mPtr, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nw / NUM_FACTEUR, nh / NUM_FACTEUR,
ntrait / NUM_FACTEUR, nrempl / NUM_FACTEUR, nepais / NUM_FACTEUR, npoint / NUM_FACTEUR));
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "addImage", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE)
exc = EX_MODPARAM;
else
{
// ajouter l'element graphique
var * x, * y, * img; // cadre englobant et n° image
hashtable_do(e, HASH_READ, param1, copy_nom(e, "X"), &x);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Y"), &y);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Image"), &img);
if(x && y && img)
{
number nx, ny, nimg;
if( var_conv_num(e, x, &nx) && var_conv_num(e, y, &ny) && var_conv_num(e, img, &nimg) )
exc = setError(p_etat, ! setPdfImage(e, &p_etat->cp, nx / NUM_FACTEUR, ny / NUM_FACTEUR, nimg / NUM_FACTEUR));
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "loadImage", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(dynCompare(e, param2, CMP_EQ, "BMP", 3))
exc = setError(p_etat, ! pdfLoadImageBmp(e, &p_etat->cp, param1));
else if(dynCompare(e, param2, CMP_EQ, "GIF", 3))
exc = setError(p_etat, ! pdfLoadImageGif(e, &p_etat->cp, param1));
else
exc = EX_MODPARAM;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "listing", 7))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
var * titre, * format;
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Titre"), &titre);
hashtable_do(e, HASH_READ, param1, copy_nom(e, "Format"), &format);
if(titre && format)
{
if(titre->type == VAR_DYNAMIC && format->type == VAR_NUMBER)
{
int cr = pdfList(e, &p_etat->cp, titre, param2, format->num / NUM_FACTEUR);
if(cr)
{
var_let(e, param2, getPdf(e, &p_etat->cp), FALSE, FALSE);
}
exc = setError(p_etat, ! cr);
}
else
exc = EX_MODPARAM;
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
+1014
View File
File diff suppressed because it is too large. Load diff
+13 -12
View File
@@ -28,8 +28,10 @@
#include "langage.h"
#include "dynamic.h"
#define RAND_STATE_COUNT 624
#define RAND_PERIOD 397
enum {
RAND_STATE_COUNT = 624,
RAND_PERIOD = 397
};
typedef struct {
int error; // dernier code erreur specifique au module
@@ -84,13 +86,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -114,7 +115,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -129,7 +130,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
@@ -137,7 +138,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -152,7 +153,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -168,7 +169,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "setSeed", 7) == 0)
else if(modFnIs(e, "setSeed", 7))
{
if(param1 == NULL)
exc = EX_MODPARAM;
@@ -180,7 +181,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
if(param1 == NULL)
exc = EX_MODPARAM;
+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;
}
+395
View File
@@ -0,0 +1,395 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// TODO version windows
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#else
#include "windows.h" // pour les fonctions FindFile...
#endif
#include "langage.h"
#include "dynamic.h"
#include "rep.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ******** PRIVATE ********************* */
static int GetInclude(env * e, Dynamic * line, Dynamic * includeFilename)
{
// check that the <line> is a include w statement. If not, return zero, else
// return in <includeFilename> the name of the include file
// separators are 9 and 32 (tab and space) and ";"" for the optional end of line comment
char * p = line->mPtr, * q;
while(*p && (*p == 9 || *p == 32)) p++;
if(*p++ != 'i') return 0;
if(*p++ != 'n') return 0;
if(*p++ != 'c') return 0;
if(*p++ != 'l') return 0;
if(*p++ != 'u') return 0;
if(*p++ != 'd') return 0;
if(*p++ != 'e') return 0;
if(*p != 9 && *p != 32) return 0;
p++;
while(*p && (*p == 9 || *p == 32)) p++;
if(*p != '\'' && *p != '"') return 0;
q = p + 1; // *p is the first char of include filename , including ' or ", and that chra must bi found at the end of the file
while(*q && (*q != *p)) q++;
if(*q != *p) return 0; // *q must be the same ' or " that begins filename
long lg = q - p - 1;
if(lg < 1) return 0;
dynLet(e, includeFilename, p + 1, lg);
dynSetLen(e, includeFilename, lg); // to be sure that \0 ends the filename
return 1;
}
/* ******** PUBLIC ********************* */
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount)
{
if(!e || !directory || !fileFound || !fileFoundCount || !duplicateCount)
return 0; // error
//
// non-recursive method : scan <path> and save each directory in <directory>'s fields. Then scan each directory and save subdirectories, in <directory>'s fields, at the end.
// And so on for each newly saved subdirectories. Finally, <directory>'s fields will contain all directories and subdirectories within <path>
// if <path> is null, <directory> already contains the list of directory to scan, else directory is setup with the directory tree.
// if <fileToSearch> is not null : <fileFound> is filled (within fields) with the full path name of each file name found.
// <fileFoundCount> contains the number of times the file was found (i.e. <fileFound> field's number)
// if <fileToSearch> is equal to "*" : means to check for duplicate files within the whole directory tree (<duplicateCount> gives the number of it),
// and so <fileFound> will contains all filenames (without path)
//
if(path)
dynSetAsSz(e, directory, (char *)path);
long nb = dynDcount(e, directory, cFM, DYN_NONE, DYN_NONE), done = 0;
//
#ifdef UNIX
DIR * dir = NULL;
struct dirent * entry = NULL;
#else
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
#endif
//
Dynamic workPath;
dynInit(e, &workPath, DYN_LGMIN);
//
*duplicateCount = 0;
*fileFoundCount = 0;
if(fileToSearch)
dynSetLen(e, fileFound, 0);
//
while(nb > done)
{
long newNb = nb;
for(long ind = done + 1; ind <= nb; ind++)
{
//dynExtractField(e, directory, ind, &workPath);
dynField(e, directory, &workPath, ind, DYN_NONE, cFM, DYN_NONE, 1);
// read each entry in directory and save subdirectory name (full path)
// TODO !? => check that workPath hasn't yet been scanned (e.g. directory link with circular reference)
#ifdef UNIX
if((dir = opendir(workPath.mPtr)) == NULL)
{
// continue to next item (no access right for example for this directory, etc.)
//dynFree(e, &workPath);
//return 0;
continue;
}
while ((entry = readdir(dir)) != NULL)
{
if(path)
{
if(entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
{
newNb++;
dynStore(e, directory, newNb, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '/')
dynConcatSz(e, directory, "/", 1);
dynConcatSz(e, directory, entry->d_name, DYN_LGNONE);
}
}
// check "regular" files (DT_REG si linux specific)
if(fileToSearch)
{
if(entry->d_type == DT_REG && *fileToSearch == '*')
{
long pos = dynLocateSz(e, fileFound, entry->d_name, cFM, DYN_NONE, DYN_NONE);
if(pos > 0)
(*duplicateCount)++; // duplicate found
else
{
(*fileFoundCount)++;
dynStoreSz(e, fileFound, *fileFoundCount, DYN_NONE, entry->d_name, DYN_LGNONE, cFM, DYN_NONE); // duplicate checking doesn't take care of the file's path
}
}
else if(entry->d_type == DT_REG && strcmp(entry->d_name, fileToSearch) == 0)
{
// file found
(*fileFoundCount)++; // found, save file's directory
dynStore(e, fileFound, *fileFoundCount, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '/')
dynConcatSz(e, fileFound, "/", 1);
dynConcatSz(e, fileFound, entry->d_name, DYN_LGNONE);
}
}
}
closedir(dir);
// end readdir
#else
dynConcatSz(e, &workPath, "\\*", DYN_LGNONE); /* sinon ko... */
if((hFind = FindFirstFile(workPath.mPtr, &FindFileData)) == INVALID_HANDLE_VALUE)
{
// continue to next item (no access right for example for this directory, etc.)
//dynFree(e, &workPath);
//return 0;
continue;
}
dynSetLen(e, &workPath, workPath.mLg - 2); // enlever \* mis a la fin...
for(int cr = -1;cr != 0;)
{
if(path)
{
if((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && strcmp(FindFileData.cFileName,".") != 0 && strcmp(FindFileData.cFileName,"..") != 0)
{
newNb++;
dynStore(e, directory, newNb, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '\\')
dynConcatSz(e, directory, "\\", 1);
dynConcatSz(e, directory, FindFileData.cFileName, DYN_LGNONE);
}
}
// check "regular" files (DT_REG si linux specific)
if(fileToSearch)
{
if( !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) &&
!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) &&
!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
if( *fileToSearch == '*')
{
long pos = dynLocateSz(e, fileFound, FindFileData.cFileName, cFM, DYN_NONE, DYN_NONE);
if(pos > 0)
(*duplicateCount)++; // duplicate found
else
{
(*fileFoundCount)++;
dynStoreSz(e, fileFound, *fileFoundCount, DYN_NONE, FindFileData.cFileName, DYN_LGNONE, cFM, DYN_NONE); // duplicate checking doesn't take care of the file's path
}
}
else if(strcmp(FindFileData.cFileName, fileToSearch) == 0)
{
// file found
(*fileFoundCount)++; // found, save file's directory
dynStore(e, fileFound, *fileFoundCount, DYN_NONE, &workPath, cFM, DYN_NONE);
if(workPath.mLg > 0 && workPath.mPtr[workPath.mLg - 1] != '\\')
dynConcatSz(e, fileFound, "\\", 1);
dynConcatSz(e, fileFound, FindFileData.cFileName, DYN_LGNONE);
}
}
//
cr = FindNextFile(hFind, &FindFileData);
}
FindClose(hFind);
#endif
}
done = nb;
nb = newNb;
}
dynFree(e, &workPath);
return 1;
}
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta)
{
int cr = 0;
char cLF = 10;
char sLF[2] = {"\n"};
char sCR[2] = {"\r"};
dynSetLen(e, source, 0);
dynSetLen(e, meta, 0);
//
Dynamic fileFound, line, include, filenameFound;
dynInit(e, &fileFound, DYN_LGMIN);
dynInit(e, &line, DYN_LGMIN);
dynInit(e, &include, DYN_LGMIN);
dynInit(e, &filenameFound, DYN_LGMIN);
//
long fileCount, dup;
for(;;)
{
if( ScanDirectory(e, NULL, directory, filename, &fileFound, &fileCount, &dup) != 1)
{
cr = 1;
break;
}
if(fileCount != 1)
{
cr = 2;
break;
}
if(dynRead(e, source, fileFound.mPtr) != DYN_OK)
{
cr = 3;
break;
}
dynErase(e, source, sCR);
//
long treeLevel = 1, currentLevel = 1, level = 0, nbMeta = 1;
dynStoreSz(e, meta, META_GLOBAL_LN, DYN_NONE, "00000001", 8, cFM, DYN_NONE);
dynStoreSz(e, meta, META_FILENAME, DYN_NONE, fileFound.mPtr, DYN_LGNONE, cFM, DYN_NONE);
dynStoreSz(e, meta, META_LOCAL_LN, DYN_NONE, "1", DYN_LGNONE, cFM, DYN_NONE);
dynStoreNumber(e, meta, META_LEVEL, DYN_NONE, currentLevel, cFM, DYN_NONE);
dynStoreSz(e, meta, META_FILETREE, DYN_NONE, (char *)filename, DYN_LGNONE, cFM, DYN_NONE);
// foreach source line
long numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE);
long numLine = 1;
for( ;numLine <= numberOfLines; )
{
dynField(e, source, &line, numLine, DYN_NONE, cLF, DYN_NONE, 1);
numLine++;
if(GetInclude(e, &line, &include))
{
if(ScanDirectory(e, NULL, directory, include.mPtr, &fileFound, &fileCount, &dup))
{
if(fileCount == 1)
{
// memo include file tree to avoid cyclic includes and get meta data
// 2 memos : one for call tree, and one for the map of files/number of lines
// call tree =>
// meta<5> = file tree, multi-valued filenames (temporary, during GetSource)
// meta data =>
// meta<1> = beginning line number, global
// meta<2> = filename
// meta<3> = local line number
// meta<4> = level
//
// if filename already presents in file tree, error (ignore include)
dynRead(e, &include, fileFound.mPtr);
dynField(e, &fileFound, &filenameFound, dynDcount(e, &fileFound, e->path_sep[0], DYN_NONE, DYN_NONE), DYN_NONE, e->path_sep[0], DYN_NONE, 1); // extract filename from full path
if(dynLocateSz(e, meta, filenameFound.mPtr, cVM, META_FILETREE, cFM) > 0)
{
cr = 4;
break;
}
// insert include file after include's line
if(include.mLg == 0) // don't insert empty file (else, local line number calculus wouldn't be correct), add one space instead
{
dynLet(e, &include, " ", 1);
}
else
{
dynErase(e, &include, sCR);
if(include.mPtr[include.mLg - 1] != cLF)
dynConcatSz(e, &include, sLF, 1); // add empty final line if there's not, else meta would have double same global line (if last line is include's line)
}
//
dynIns(e, source, numLine, DYN_NONE, &include, cLF, DYN_NONE);
long nbInclude = dynDcount(e, &include, cLF, DYN_NONE, DYN_NONE);
numberOfLines = dynDcount(e, source, cLF, DYN_NONE, DYN_NONE); // extending scope
//
// put in <include> the line number formatted 00000000 and split current block in three
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
long pos = abs(dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM));
dynIns(e, meta, META_GLOBAL_LN, pos, &include, cFM, cVM);
dynIns(e, meta, META_FILENAME, pos, &fileFound, cFM, cVM);
dynInsSz(e, meta, META_LOCAL_LN, pos, "1", 1, cFM, cVM);
level = dynFieldAsNumber(e, meta, META_LEVEL, pos - 1, cFM, cVM);
dynInsNumber(e, meta, META_LEVEL, pos, level + 1, cFM, cVM);
currentLevel = level + 1;
//
dynField(e, meta, &include, 2, pos - 1, cFM, cVM, 1);
dynIns(e, meta, META_FILENAME, pos + 1, &include, cFM, cVM);
dynFmtNumber(e, numLine + nbInclude, &include, 'R', '0', 8);
dynIns(e, meta, META_GLOBAL_LN, pos + 1, &include, cFM, cVM);
long global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, pos - 1, cFM, cVM);
long local = dynFieldAsNumber(e, meta, META_LOCAL_LN, pos - 1, cFM, cVM);
dynInsNumber(e, meta, META_LOCAL_LN, pos + 1, numLine - global + local, cFM, cVM);
dynInsNumber(e, meta, META_LEVEL, pos + 1, level, cFM, cVM);
//
// adjust starting line of next blocks
nbMeta = dynDcount(e, meta, cVM, META_FILENAME, cFM);
for(long cpt = pos + 2; cpt <= nbMeta; cpt++)
{
global = dynFieldAsNumber(e, meta, META_GLOBAL_LN, cpt, cFM, cVM);
dynFmtNumber(e, global + nbInclude, &include, 'R', '0', 8);
dynStore(e, meta, META_GLOBAL_LN, cpt, &include, cFM, cVM);
}
//
dynStore(e, meta, META_FILETREE, ++treeLevel, &filenameFound, cFM, cVM);
}
else
{
cr = 5; // if fileCount <> 1, error (multiple included include not autorized, or not found when filename includes dot or path separator char)
break;
}
}
else
{
cr = 6; // if error while searching for the include file, error
break;
}
}
// delete last file in call tree when changing of file
dynFmtNumber(e, numLine, &include, 'R', '0', 8);
long pos = dynSortLocateSz(e, meta, include.mPtr, cVM, DYN_SORT_ASC, META_GLOBAL_LN, cFM);
if(pos < 0)
pos = abs(pos) - 1;
if(pos > nbMeta)
pos = nbMeta;
level = dynFieldAsNumber(e, meta, META_LEVEL, pos, cFM, cVM);
if(level < currentLevel)
dynDel(e, meta, META_FILETREE, treeLevel--, cFM, cVM, 1);
currentLevel = level;
}
dynDel(e, meta, META_FILETREE, DYN_NONE, cFM, DYN_NONE, 1);
break;
}
//
dynFree(e, &fileFound);
dynFree(e, &line);
dynFree(e, &include);
dynFree(e, &filenameFound);
return cr;
}
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine)
{
indice = (indice - 1) * META_NB;
dynFmtNumber(e, lineNumber, fileFound, 'R', '0', 8);
long pos = dynSortLocateSz(e, meta, fileFound->mPtr, cVM, DYN_SORT_ASC, indice + META_GLOBAL_LN, cFM);
if(pos < 0)
pos = abs(pos) - 1;
//
*ficLine = lineNumber - dynFieldAsNumber(e, meta, indice + META_GLOBAL_LN, pos, cFM, cVM) + dynFieldAsNumber(e, meta, indice + META_LOCAL_LN, pos, cFM, cVM);
dynField(e, meta, fileFound, indice + META_FILENAME, pos, cFM, cVM, 1);
}
+44
View File
@@ -0,0 +1,44 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifndef REP_H
#define REP_H
#include "apidecl.h"
enum {
META_GLOBAL_LN = 1,
META_FILENAME = 2,
META_LOCAL_LN = 3,
META_LEVEL = 4,
META_FILETREE = 5,
META_WSRC = 5,
META_NB = 5
};
WAPIDECL long ScanDirectory(env * e, const char * path, Dynamic * directory, const char * fileToSearch, Dynamic * fileFound, long * fileFoundCount, long * duplicateCount);
WAPIDECL long GetSource(env * e, Dynamic * directory, const char * filename, Dynamic * source, Dynamic * meta);
WAPIDECL void GetFile(env * e, long lineNumber, Dynamic * meta, int indice, Dynamic * fileFound, long * ficLine);
/* ********************************************** */
#endif
+53
View File
@@ -0,0 +1,53 @@
/* **********************************************
__ __ __
\ \/ \/ / 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_MEM_ERROR = -2,
WSECURESOCKET_ERROR = -1,
WSECURESOCKET_OK = 0,
};
typedef struct {
modContextSocket ctxSock;
SSL_CTX * clientSecureCtx;
SSL_CTX * serverSecureCtx;
SSL * sslServer;
SSL * sslClient;
int packet; /* taille des paquets en lecture */
} modContextSecureSocket;
WAPIDECL void initSecureSock(env * e, modContextSecureSocket * ctx);
WAPIDECL void freeSecureSock(env * e, modContextSecureSocket * ctx);
WAPIDECL long SetPemCertificate(env * e, modContextSecureSocket * ctx, Dynamic * cert, Dynamic * key);
WAPIDECL long SecureSocketServer(env * e, modContextSecureSocket * ctx, Socket sock); /* secure socket from server accept */
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server);
WAPIDECL long ReadSecureSocket(env * e, modContextSecureSocket * ctx, SSL * ssl, var * data, long timeoutMs);
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, SSL * ssl, var * data);
+378
View File
@@ -0,0 +1,378 @@
/* **********************************************
__ __ __
\ \/ \/ / 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;
enum {
EXMOD_SECURESOCK_SERVER_PORT_NUM = 1,
EXMOD_SECURESOCK_SERVER_PORT_INVALID = 2,
EXMOD_SECURESOCK_NEW = 3,
EXMOD_SECURESOCK_SETSERVER = 4,
EXMOD_SECURESOCK_CONNECT = 5,
EXMOD_SECURESOCK_WAIT = 6,
EXMOD_SECURESOCK_ACCEPT = 7,
EXMOD_SECURESOCK_READ = 8,
EXMOD_SECURESOCK_WRITE = 9,
EXMOD_SECURESOCK_SECURESERVER = 10,
EXMOD_SECURESOCK_SECURECLIENT = 11,
EXMOD_SECURESOCK_SETCERTIFICATE = 12
};
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// fonction createServer, arret
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
initSecureSock(e, &p_etat->ctxSecureSock);
}
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
freeSecureSock(e, &p_etat->ctxSecureSock);
//***
memfree(e, p_etat);
}
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
{
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
/* extend error */
if(param2 != NULL)
if(param2->type == VAR_NUMBER)
param2->num = (ent64)(NUM_FACTEUR * p_etat->ctxSecureSock.ctxSock.err);
}
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(modFnIs(e, "server", 6))
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
return (exc = EX_MODETAT);
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER && param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
// param<1> = numero de port
number port;
if( ! var_conv_num(e, param1, &port))
exc = setError(p_etat, EXMOD_SECURESOCK_SERVER_PORT_NUM);
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)
{
// TODO Certificats
if(SetPemCertificate(e, &p_etat->ctxSecureSock, NULL, NULL) == WSECURESOCKET_OK)
{
if(SecureSocketServer(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock) == WSECURESOCKET_OK)
{
exc = OK;
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_SECURESERVER);
}
}
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))
{
/* connexion a un serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || (param2->type != VAR_NUMBER && param2->type != VAR_DYNAMIC) || param3->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
// param1 = host (nom ou ip)
// param2 = port
// param3 = socket cliente en retour
number port;
if( ! var_conv_num(e, param2, &port))
exc = setError(p_etat, EXMOD_SECURESOCK_SERVER_PORT_NUM);
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), param1) == WSOCKET_OK)
{
if(SecureSocketClient(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.ctxSock.sock, param1) == WSECURESOCKET_OK)
{
param3->num = p_etat->ctxSecureSock.ctxSock.sock; /* (sock * NUM_FACTEUR) ? */
exc = OK;
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_SECURECLIENT);
}
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_CONNECT);
}
}
else
{
exc = setError(p_etat, EXMOD_SECURESOCK_NEW);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stopServer", 10))
{
/* arret serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
// A REVOIR
FreeSocket(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock);
p_etat->ctxSecureSock.ctxSock.servSock = INVALID_SOCKET;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "stop", 4))
{
/* arret connexion cliente */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
// A REVOIR
FreeSocket(e, &p_etat->ctxSecureSock.ctxSock, param1->num);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "wait", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
// attend une activite sur la socket serveur et si oui cree une nouvelle socket, timeout en secondes
long cr = WaitOneSocketForRead(e, &p_etat->ctxSecureSock.ctxSock, p_etat->ctxSecureSock.ctxSock.servSock, param1->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SECURESOCK_WAIT);
else if(cr == 0)
param2->num = NUM_MOINSUN; /* => timeout, RAS */
else
{
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSecureSock.ctxSock) == WSOCKET_OK)
{
param2->num = p_etat->ctxSecureSock.ctxSock.sock;
}
else
exc = setError(p_etat, EXMOD_SECURESOCK_ACCEPT);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
/* lecture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
/* lire par paquets de longueur fixe et s'arreter des que plus rien a lire
lecture par paquets de <pas> octets
param1 = socket, param2 = chaine lue, param3 = timeout en secondes
*/
long cr = WaitOneSocketForRead(e, &p_etat->ctxSecureSock.ctxSock, param1->num, param3->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SECURESOCK_WAIT);
else if(cr == 0)
dynSetLen(e, param2, 0); /* => timeout, RAS */
else
{
/* socket a recu des donnees */
if(ReadSocket(e, &p_etat->ctxSecureSock.ctxSock, param1->num, param2, param3->num * 1000 / NUM_FACTEUR) != WSOCKET_OK)
/* traiter le cas WSOCKET_END_CONNECT : erreur ? (fin cnx) */
exc = setError(p_etat, EXMOD_SECURESOCK_READ);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "set", 3))
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
/* param1 = socket, param2 = chaine a ecrire */
if(WriteSecureSocket(e, &p_etat->ctxSecureSock, p_etat->ctxSecureSock.sslClient, param2) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SECURESOCK_WRITE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
}
//
return exc;
}
+193
View File
@@ -0,0 +1,193 @@
/* **********************************************
__ __ __
\ \/ \/ / 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
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 ************************ */
/* ****** PUBLIC ************************ */
WAPIDECL void initSecureSock(env * e, modContextSecureSocket * ctx)
{
initSock(e, &ctx->ctxSock);
/* */
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
/* */
ctx->clientSecureCtx = SSL_CTX_new(TLS_client_method());
/* Activer la vérification */
SSL_CTX_set_verify(ctx->clientSecureCtx, SSL_VERIFY_PEER, NULL);
/* Charger les autorités de confiance */
if (!SSL_CTX_load_verify_locations(ctx->clientSecureCtx, "/etc/ssl/certs/ca-certificates.crt", NULL))
; // erreur : quid ?
/* */
ctx->serverSecureCtx = SSL_CTX_new(TLS_server_method());
/* */
ctx->packet = 16000;
}
WAPIDECL void freeSecureSock(env * e, modContextSecureSocket * ctx)
{
/* SSL_shutdown(ctx->sslXXX) ? */
SSL_free(ctx->sslClient);
SSL_free(ctx->sslServer);
/* */
SSL_CTX_free(ctx->clientSecureCtx);
SSL_CTX_free(ctx->serverSecureCtx);
/* */
freeSock(e, &ctx->ctxSock);
}
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)
{
/* secure socket from server accept */
ctx->sslServer = SSL_new(ctx->serverSecureCtx);
SSL_set_fd(ctx->sslServer, sock);
if(SSL_accept(ctx->sslServer) <= 0)
return WSECURESOCKET_ERROR;
else
return WSECURESOCKET_OK;
}
WAPIDECL long SecureSocketClient(env * e, modContextSecureSocket * ctx, Socket sock, var * server)
{
/* secure socket connected to a server */
ctx->sslClient = SSL_new(ctx->clientSecureCtx);
SSL_set_fd(ctx->sslClient, sock);
if(SSL_connect(ctx->sslClient) <= 0)
return WSECURESOCKET_ERROR;
else
{
if(SSL_get_verify_result(ctx->sslClient) != X509_V_OK)
return WSECURESOCKET_ERROR;
X509 * cert;
if( ! (cert = SSL_get_peer_certificate(ctx->sslClient)) )
return WSECURESOCKET_ERROR;
int cr = X509_check_host(cert, server->mPtr, 0, 0, NULL);
X509_free(cert);
if(cr != 1)
return WSECURESOCKET_ERROR;
/* */
return WSECURESOCKET_OK;
}
}
WAPIDECL long ReadSecureSocket(env * e, modContextSecureSocket * ctx, SSL * ssl, var * data, long timeoutMs)
{
int packetLg = ctx->packet;
for(;;)
{
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
{
return WSECURESOCKET_MEM_ERROR; // erreur memoire
}
int nbRead = SSL_read(ssl, data->mPtr + data->mLg, packetLg);
if(nbRead < 0)
return WSECURESOCKET_ERROR;
dynSetLen(e, data, data->mLg + nbRead);
if(nbRead < packetLg)
return WSECURESOCKET_OK;
}
}
WAPIDECL long WriteSecureSocket(env * e, modContextSecureSocket * ctx, SSL * ssl, var * data)
{
SSL_write(ssl, data->mPtr, data->mLg);
return WSECURESOCKET_OK;
}
+73
View File
@@ -0,0 +1,73 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef WINLIB
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#else
#include <windows.h>
#endif
#include "langage.h"
#ifdef WINLIB
typedef int key_t;
#endif
/* codes a passer a la fonction setError */
enum {
EXMOD_BUFFER_INIT = 1,
EXMOD_BUFFER_WRITE = 2
};
typedef struct {
// proprietaire
key_t cle;
char nom[24]; // 23 cars + \0
long taille;
var * buffer;
#ifndef WINLIB
int handle;
int semId;
#else
HANDLE handle;
char semDesti[25]; // 23 cars + '#' + \0 (different desti sinon ko sous windows)
HANDLE newProcess; // writer: handle process creee en SUSPEND, reader : handle passe en arg et convertit en num
#endif
// destinataire
char desti[24]; // 23 cars + \0
// message lu/ecrit
var * message;
} modContextShm;
WAPIDECL void initShm(env * e, modContextShm * ctx);
WAPIDECL void freeShm(env * e, modContextShm * ctx);
WAPIDECL long readShm(env * e, modContextShm * ctx);
WAPIDECL long writeShm(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx);
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx);
+181
View File
@@ -0,0 +1,181 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "langage.h"
#include "dynamic.h"
#include "hashtable.h"
#include "shm.h"
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modContextShm cs;
} modEtat;
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
var * prog;
hashtable_do(e, HASH_READ, &e->g, copy_nom(e, GUV_PROG), &prog);
// maj ctx avec _prog et taille
*((ent64 *)(p_etat->cs.nom)) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 1) = 0;
*(((ent64 *)(p_etat->cs.nom)) + 2) = 0;
if(prog && prog->type == VAR_DYNAMIC && prog->mLg < 24)
strncpy(p_etat->cs.nom, prog->mPtr, prog->mLg);
p_etat->cs.taille = 4000;
//
initShm(e, &p_etat->cs);
}
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
{
freeShm(e, &p_etat->cs);
//*** FIN du code specifique ici
memfree(e, p_etat);
}
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
p_etat->cs.message = param1;
exc = setError(p_etat, readShm(e, &p_etat->cs));
// param1 vide si rien a lire
}
}
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
*((ent64 *)(p_etat->cs.desti)) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 1) = 0;
*(((ent64 *)(p_etat->cs.desti)) + 2) = 0;
if(param1->mLg < 24)
strncpy(p_etat->cs.desti, param1->mPtr, param1->mLg);
p_etat->cs.message = param2;
exc = setError(p_etat, writeShm(e, &p_etat->cs));
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
}
//
return exc;
}
/* **************************************************************************************************** */
+491
View File
@@ -0,0 +1,491 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "shm.h"
#include "buffer.h"
#include "dynamic.h"
#include <errno.h>
#ifndef WINLIB
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
enum {
NBSEM = 1
};
/* ****** PRIVATE ************************ */
static key_t Hash32(const char * cle, int lg)
{
// lg multiple de 4 et > 0
// cle est une zone memoire de lg cars
ent64 k, h = 0;
if(lg > 0 && (lg % 4 == 0))
{
h = *(int *)cle;
for(int i = 0; i < lg; )
{
k = (ent64)cle[i++];
k |= ((ent64)cle[i++]) << 8;
k |= ((ent64)cle[i++]) << 16;
k |= ((ent64)cle[i++]) << 24;
k *= 0xcc9e2d51;
k = (k << 15) | (k >> 17); // 32 - 15
k *= 0x1b873593;
h ^= k;
h = (h << 13) | (h >> 19); // 32 - 13
h = h * 5 + 0xe6546b64;
}
}
h ^= lg;
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return (key_t)h;
}
/* ****** PUBLIC ************************ */
WAPIDECL void initShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
ctx->buffer = NULL;
ctx->handle = -1;
ctx->semId = -1;
// creer la sharedmemory du process, pour lecture
// ne pas controler la taille, sera fait par 'shmget'
// calculer la cle a partir du nom du prog (ctx->nom)
ctx->cle = Hash32(ctx->nom, 24); // chaine de 23 cars max + \0 de fin
// securite : supprimer un eventuel reliquat d'un ancien shm ? Faire un appel externe pas systematique, que le createur, (ou mettre un flag)
//shmctl(ctx->cle, IPC_RMID, NULL);
// creer le buffer
ctx->handle = shmget(ctx->cle, ctx->taille, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(ctx->handle < 0)
return; // erreur creation sharedmemory
// lire le pointeur
ctx->buffer = (var *)shmat(ctx->handle, NULL, 0);
if(ctx->buffer == (var *)(-1))
{
shmctl(ctx->handle, IPC_RMID, NULL);
ctx->buffer = NULL;
ctx->handle = -1;
return; // erreur recup pointeur
}
// creer le semaphore pour les writers
ctx->semId = semget(ctx->cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(ctx->semId < 0)
{
freeShm(e, ctx); // erreur
return;
}
// init semaphore
unsigned short table[NBSEM];
table[0] = 1;
if(semctl(ctx->semId, 0, SETALL, table) < 0)
{
freeShm(e, ctx); // erreur
return;
}
#else
ctx->buffer = NULL;
ctx->handle = NULL;
strncpy(ctx->semDesti, ctx->desti, 24);
ctx->semDesti[24] = 0;
ctx->semDesti[strlen(ctx->desti)] = '#';
// creer la sharedmemory du process, pour lecture
// ne pas controler la taille, sera fait par 'CreateFileMapping'
// la cle est directement le nom
// creer le buffer
ctx->handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->taille, ctx->nom); // NULL si ko, attention au \0 de fin de ctx->nom
if( ! ctx->handle)
return; // erreur creation sharedmemory
ctx->buffer = (var *)MapViewOfFile(ctx->handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! ctx->buffer)
{
CloseHandle(ctx->handle);
ctx->buffer = NULL;
ctx->handle = NULL;
return; // erreur recup pointeur
}
#endif
ctx->buffer->type = VAR_BUFFER;
ctx->buffer->lgmax = ctx->taille - sizeof(var);
ctx->buffer->read = 0;
ctx->buffer->write = 0;
ctx->buffer->ptr = NULL; // NULL signifie que le contenu est a la suite de l'entete de la variable (utilise uniquement ici avec les IPC)
}
WAPIDECL void freeShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
if(ctx->buffer)
shmdt(ctx->buffer);
if(ctx->handle >= 0)
shmctl(ctx->handle, IPC_RMID, NULL);
if(ctx->semId >= 0)
semctl(ctx->semId, IPC_RMID, 0);
ctx->buffer = NULL;
ctx->handle = -1;
ctx->semId = -1;
#else
if(ctx->buffer)
UnmapViewOfFile(ctx->buffer);
if(ctx->handle >= 0)
CloseHandle(ctx->handle); // verif que bien detruit
ctx->buffer = NULL;
ctx->handle = NULL;
#endif
}
WAPIDECL long readShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
if( ! ctx->buffer || ctx->handle < 0)
return EXMOD_BUFFER_INIT;
#else
if( ! ctx->buffer || ! ctx->handle)
return EXMOD_BUFFER_INIT;
#endif
buffer_read(e, ctx->buffer, ctx->message);
// e->exception != OK si exception en lecture (que EX_MEM) ! vide si rien a lire (Dynamic)
return e->exception;
}
WAPIDECL long writeShm(env * e, modContextShm * ctx)
{
#ifndef WINLIB
// calculer la cle a partir du nom du prog (ctx->nom)
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au buffer
int handle = shmget(cle, 0, 0);
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
var * buffer = (var *)shmat(handle, NULL, 0);
if(buffer == (var *)(-1))
return EXMOD_BUFFER_WRITE; // seul le ptr se libere
// prendre le verrou (semaphore) pour ecrire, avec attente
int semId = semget(cle, NBSEM, 0);
if(semId < 0)
{
shmdt(buffer);
return EXMOD_BUFFER_WRITE;
}
struct sembuf bufw;
bufw.sem_num = 0;
bufw.sem_op = -1; // prendre
bufw.sem_flg = SEM_UNDO; // | IPC_NOWAIT ?
if(semop(semId, &bufw, 1) < 0)
{
shmdt(buffer);
return EXMOD_BUFFER_WRITE;
}
// EcrireBuffer
buffer_write(e, buffer, ctx->message);
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
// liberer le verrou
bufw.sem_op = 1; // liberer
semop(semId, &bufw, 1);
// ne liberer que le ptr sous unix
shmdt(buffer);
#else
// la cle est directement le destinataire
HANDLE handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, ctx->desti); // attention au \0 de fin
if( ! handle)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
var * buffer = (var *)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! buffer)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// prendre le verrou (semaphore) pour ecrire, avec attente
HANDLE hSem = CreateSemaphore(NULL, 1, 1, ctx->semDesti); // NULL si erreur
if( ! hSem)
{
UnmapViewOfFile(buffer);
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
if(WaitForSingleObject(hSem, 0) != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur ; 0 = timeout en secondes
{
ReleaseSemaphore(hSem, 1, NULL);
UnmapViewOfFile(buffer);
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// EcrireBuffer
buffer_write(e, buffer, ctx->message);
// e->exception != OK si exception en ecriture (que EX_BUFOVF) !
// liberer le verrou
ReleaseSemaphore(hSem, 1, NULL);
// liberations
UnmapViewOfFile(buffer);
CloseHandle(handle);
#endif
return e->exception;
}
WAPIDECL long newProcessShmWriter(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, ctx->message->lg + sizeLg, IPC_CREAT | IPC_EXCL | 0666); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// ne liberer que le ptr sous unix
shmdt(data);
#else
// la cle est directement le destinataire
HANDLE handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, ctx->message->lg + sizeLg, ctx->desti); // attention au \0 de fin
if( ! handle)
return EXMOD_BUFFER_WRITE; // erreur access
// lire le pointeur
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Ecrire les donnees
memset(data, 0, sizeLg);
strcpy((char *)data, Int64ToSz(e, ctx->message->lg, FALSE, sizeLg - 1));
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
// dupliquer le HANDLE sur le mapping
HANDLE dup = NULL;
if( ! DuplicateHandle(GetCurrentProcess(), handle, ctx->newProcess, &dup, 0, FALSE, DUPLICATE_SAME_ACCESS))// FALSE : le handle dupliqué n’a pas besoin d’être héritable
e->exception = EXMOD_BUFFER_WRITE;
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
WAPIDECL long newProcessShmReader(env * e, modContextShm * ctx)
{
int sizeLg = 20;
#ifndef WINLIB
key_t cle = Hash32(ctx->desti, 24); // chaine de 23 cars + \0
// acceder au message (type Dynamic, a controler ?)
int handle = shmget(cle, 0, 0); // < 0 si ko
if(handle < 0)
return EXMOD_BUFFER_WRITE; // erreur access TODO revoir les erreurs
// lire le pointeur
pointeur data = (pointeur)shmat(handle, NULL, 0);
if(data == (pointeur)(-1))
{
shmctl(handle, IPC_RMID, NULL);
return EXMOD_BUFFER_WRITE;
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// ne liberer que le ptr sous unix
shmdt(data);
shmctl(handle, IPC_RMID, NULL);
#else
// lire le pointeur, a partir du handle lu de la ligne de commande
HANDLE handle = ctx->newProcess;
pointeur data = (pointeur)MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if( ! data)
{
CloseHandle(handle);
return EXMOD_BUFFER_WRITE; // erreur recup pointeur
}
// Lire les donnees
long err, lg = dynSzToNum(e, (char *)data, FALSE, sizeLg - 1, &err);
if( ! dynCtrl(e, ctx->message, lg, FALSE))
dynSetLen(e, ctx->message, 0);
else
{
dynSetLen(e, ctx->message, lg);
memcpy(data + sizeLg, ctx->message->ptr, ctx->message->lg);
}
// liberations
UnmapViewOfFile(data);
CloseHandle(handle);
#endif
return e->exception;
}
#ifndef WINLIB
WAPIDECL int OpenLock(env * e, const char * name)
{
key_t cle = Hash32(name, 24); // chaine de 23 cars max + \0 de fin
int semId = semget(cle, NBSEM, IPC_CREAT | IPC_EXCL | 0666);
if(semId < 0)
{
if(errno != EEXIST)
return -1; // erreur
// deja cree, ok
semId = semget(cle, NBSEM, 0);
if(semId < 0)
{
return -1; // erreur
}
}
else
{
// init semaphore
unsigned short table[NBSEM];
table[0] = 1;
if(semctl(semId, 0, SETALL, table) < 0)
{
semctl(semId, IPC_RMID, 0);
return -1; // erreur
}
}
return semId; // >=0 : ok
}
#else
WAPIDECL HANDLE OpenLock(env * e, const char * name)
{
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
char fullName[40] = {0};
if(strlen(name) > 23)
return NULL; // nom trop long
//
strcpy(fullName, "Global\\");
strcat(fullName, name);
HANDLE hSem = CreateSemaphore(&sa, 1, 1, fullName); // 1 = valeur initiale du semaphore ; 1 = valeur max du semaphore ; nom du semaphore (unique)
if( ! hSem)
return NULL; // erreur (si existe, ne passe pas ici, hSem est renseigne avec le sem existant) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur, dans ce cas hSem n'est pas NULL
else
return hSem;
}
#endif
#ifndef WINLIB
WAPIDECL void CloseLock(env * e, int semId)
{
if(semId >= 0)
semctl(semId, IPC_RMID, 0);
}
#else
WAPIDECL void CloseLock(env * e, HANDLE hSem)
{
CloseHandle(hSem);
}
#endif
#ifndef WINLIB
WAPIDECL int SetLock(env * e, int semId, int milliSec)
{
// prendre le verrou (semaphore) pour ecrire, avec attente
struct sembuf bufw;
struct timespec ts;
ts.tv_sec = milliSec / 1000;
ts.tv_nsec = (milliSec % 1000) * 1000000; // xxx ms
bufw.sem_num = 0;
bufw.sem_op = -1; // prendre
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
if(semop(semId, &bufw, 1) < 0)
{
if(errno != EAGAIN)
return -1; // erreur : semaphore ko
// semaphore pris : attendre et reessayer une fois
nanosleep(&ts, NULL);
if(semop(semId, &bufw, 1) < 0)
{
if(errno != EAGAIN)
return -1; // erreur : semaphore ko
return 0; // sortie en timeout cette fois
}
}
return 1; // ok
}
#else
WAPIDECL int SetLock(env * e, HANDLE hSem, int milliSec)
{
int cr = WaitForSingleObject(hSem, milliSec);
if( cr != WAIT_OBJECT_0) // retour WAIT_OBJECT_0 si ok, WAIT_TIMEOUT ou autre si pas dispo ou erreur
{
// semaphore pris : attendre ?
if(cr != WAIT_TIMEOUT)
return -1; // erreur
// sortie en time out, semaphore pris, attendre ?
return 0;
}
return 1;
}
#endif
#ifndef WINLIB
WAPIDECL void UnsetLock(env * e, int semId)
{
// liberer le verrou
struct sembuf bufw;
bufw.sem_num = 0;
bufw.sem_op = 1; // liberer
bufw.sem_flg = SEM_UNDO | IPC_NOWAIT;
semop(semId, &bufw, 1);
}
#else
WAPIDECL void UnsetLock(env * e, HANDLE hSem)
{
// liberer le semaphore
ReleaseSemaphore(hSem, 1, NULL);
}
#endif
+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 <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
};
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 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);
+188 -346
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -29,32 +29,39 @@
#include <errno.h>
#ifdef UNIX
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <netdb.h>
#else
#include "windows.h"
#include "winsock2.h"
#include "windows.h"
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.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 ?)
modContextSocket ctxSock;
} modEtat;
/* 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
};
static int setError(modEtat * p, int err)
{
@@ -63,30 +70,36 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// fonction createServer, arret
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -97,414 +110,243 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
p_etat->mSocket = 0;
p_etat->mServeur = 0;
initSock(e, &p_etat->ctxSock);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
//***
if(p_etat->mSocket > 0)
close(p_etat->mSocket);
freeSock(e, &p_etat->ctxSock);
//***
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
if(param1 == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
if(param1->type == VAR_NUMBER)
{
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
/* extend error */
if(param2 != NULL)
if(param2->type == VAR_NUMBER)
param2->num = (ent64)(NUM_FACTEUR * p_etat->ctxSock.err);
}
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "server", 6) == 0)
else if(modFnIs(e, "server", 6))
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
{
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;
}
return (exc = EX_MODETAT);
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER && param1->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;
}
{
// param<1> = numero de port
number port;
if( ! var_conv_num(e, param1, &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 = OK;
}
else
{
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)
exc = EX_MODPARAM; /* erreur */
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || (param2->type != VAR_NUMBER && param2->type != VAR_DYNAMIC) || param3->type != VAR_NUMBER)
exc = EX_MODPARAM;
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 */
}
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
{
p_etat->mServeur = 2; /* client */
#ifdef UNIX
sigemptyset(&p_etat->mOldBlockSig);
sigfillset(&p_etat->mBlockSig);
#endif
// param1 = host (nom ou ip)
// param2 = port
// param3 = socket cliente en retour
number port;
if( ! var_conv_num(e, param2, &port))
exc = setError(p_etat, EXMOD_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), param1) == WSOCKET_OK)
{
param3->num = p_etat->ctxSock.sock; /* (sock * NUM_FACTEUR) ? */
exc = OK;
}
else
{
exc = setError(p_etat, EXMOD_SOCK_CONNECT);
}
}
else
{
exc = setError(p_etat, EXMOD_SOCK_NEW);
}
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "arret", 5) == 0)
else if(modFnIs(e, "stopServer", 10))
{
/* arret connexion cliente ou serveur */
if(p_etat != NULL)
/* arret serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
shutdown(p_etat->mSocket, 2);
close(p_etat->mSocket);
p_etat->mSocket = 0;
FreeSocket(e, &p_etat->ctxSock, p_etat->ctxSock.servSock);
p_etat->ctxSock.servSock = INVALID_SOCKET;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "attente", 7) == 0)
else if(modFnIs(e, "stop", 4))
{
/* arret connexion cliente */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
FreeSocket(e, &p_etat->ctxSock, param1->num);
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "wait", 4))
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_NUMBER)
else if(param1->type != VAR_NUMBER || param2->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
}
// attend une activite sur la socket serveur et si oui cree une nouvelle socket, timeout en secondes
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, p_etat->ctxSock.servSock, param1->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
param2->num = NUM_MOINSUN; /* => timeout, RAS */
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);
/* nouvelle connexion entrante */
if(AcceptClientSocket(e, &p_etat->ctxSock) == WSOCKET_OK)
{
param2->num = p_etat->ctxSock.sock;
}
else
exc = setError(p_etat, EXMOD_SOCK_ACCEPT);
}
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)
else if(modFnIs(e, "get", 3))
{
long nblu = 0, arg = 1, flagInProgress = 0, pas = 16000, would_block;
/* lecture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_DYNAMIC)
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC || param3->type != VAR_NUMBER)
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
/* lire par paquets de longueur fixe et s'arreter des que plus rien a lire
lecture par paquets de <pas> octets
param1 = socket, param2 = chaine lue, param3 = timeout en secondes
*/
long cr = WaitOneSocketForRead(e, &p_etat->ctxSock, param1->num, param3->num * 1000 / NUM_FACTEUR);
if(cr < 0)
exc = setError(p_etat, EXMOD_SOCK_WAIT);
else if(cr == 0)
dynSetLen(e, param2, 0); /* => timeout, RAS */
else
{
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 */
/* socket a recu des donnees */
if(ReadSocket(e, &p_etat->ctxSock, param1->num, param2, param3->num * 1000 / NUM_FACTEUR) != WSOCKET_OK)
/* traiter le cas WSOCKET_END_CONNECT : erreur ? (fin cnx) */
exc = setError(p_etat, EXMOD_SOCK_READ);
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "accept", 6) == 0)
else if(modFnIs(e, "set", 3))
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param == NULL)
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param->type != VAR_NUMBER)
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC)
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 */
/* param1 = socket, param2 = chaine a ecrire */
if(WriteSocket(e, &p_etat->ctxSock, param1->num, param2) != WSOCKET_OK)
exc = setError(p_etat, EXMOD_SOCK_WRITE);
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = EX_MODFUNC; // fonction non prise en charge
if(p_etat == NULL)
exc = EX_MODETAT;
else
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
}
//
return exc;
+591
View File
@@ -0,0 +1,591 @@
/* **********************************************
__ __ __
\ \/ \/ / 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 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
/* */
/* 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
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;
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;
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;
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;
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(;;)
{
// TODO ajouter WaitOneSocketForWrite()
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
*/
+211 -61
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -25,22 +25,23 @@
#include <time.h>
#include <string.h>
#ifdef UNIX
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#ifdef WINLIB
#include "windows.h"
#else
#include "windows.h" // TODO ici
#include <dirent.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#endif
#include "langage.h"
#include "dynamic.h"
#include "var.h"
typedef struct {
int error; // dernier code erreur specifique au module
@@ -49,13 +50,15 @@ typedef struct {
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_SYSTEM_FICTMP 1
#define EXMOD_SYSTEM_UNKNOWNVARENV 2
#define EXMOD_SYSTEM_SETENV 3
#define EXMOD_SYSTEM_UNSETENV 4
#define EXMOD_SYSTEM_GETHOST 5
#define EXMOD_SYSTEM_UNAME 6
#define EXMOD_SYSTEM_FORK 7
enum {
EXMOD_SYSTEM_FICTMP = 1,
EXMOD_SYSTEM_UNKNOWNVARENV = 2,
EXMOD_SYSTEM_SETENV = 3,
EXMOD_SYSTEM_UNSETENV = 4,
EXMOD_SYSTEM_GETHOST = 5,
EXMOD_SYSTEM_UNAME = 6,
EXMOD_SYSTEM_FORK = 7
};
static int setError(modEtat * p, int err)
{
@@ -64,13 +67,12 @@ static int setError(modEtat * p, int err)
return EX_MODERR;
}
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
@@ -100,7 +102,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -113,7 +115,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//*** code specifique ici
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
@@ -122,7 +124,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
memfree(e, p_etat);
}
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
@@ -132,7 +134,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -146,14 +148,14 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "execute", 7) == 0)
else if(modFnIs(e, "execute", 7))
{
p_etat->error = 0;
// execute(command, returning, capturing)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_NUMBER)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
@@ -166,20 +168,30 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
if(flagCapturing && exc == OK)
{
dynSetLen(e, param3, 0);
#ifdef WINLIB
if (!GetTempPathA(param3->mLgmax, param3->mPtr))
exc = EXMOD_SYSTEM_FICTMP;
else if(!GetTempFileNameA(param3->mPtr, "tmp", 0, e->int_dynamic.mPtr))
exc = EXMOD_SYSTEM_FICTMP;
#else
int fd; // pour avoir un nom de fichier temporaire
dynLet(e, &e->int_dynamic, "/tmp/cap_XXXXXX", 15);
if((fd = mkstemp(e->int_dynamic.mPtr)) == -1)
exc = EXMOD_SYSTEM_FICTMP;
else
close(fd);
#endif
}
if(exc == OK)
{
if(flagCapturing)
{
dynIns(e, &e->int_dynamic, 1, DYN_NONE, param3, '>', DYN_NONE);
cr = system(param1->mPtr);
dynSetAs(e, param3, param1);
dynIns(e, param3, 1 + dynDcount(e, param3, '>', DYN_NONE, DYN_NONE), DYN_NONE, &e->int_dynamic, '>', DYN_NONE);
cr = system(param3->mPtr);
dynRead(e, param3, e->int_dynamic.mPtr);
// purge fichier temp
remove(e->int_dynamic.mPtr); // pbm windows ?!
}
else
{
@@ -190,14 +202,14 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getEnv", 6) == 0)
else if(modFnIs(e, "getEnv", 6))
{
p_etat->error = 0;
/* utilisation de dynRead qui fait le travail */
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
@@ -215,72 +227,110 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "createEnv", 9) == 0)
else if(modFnIs(e, "createEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
// verifier si existe avec getenv, si oui erreur
char * varenv = getenv(param1->mPtr);
if(varenv)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
else if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
#else
int cr = setenv(param1->mPtr, param2->mPtr, 0); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "updateEnv", 9) == 0)
else if(modFnIs(e, "updateEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, param2->mPtr))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
#else
int cr = setenv(param1->mPtr, param2->mPtr, 1); // 1 = overwrite, 0 = ne pas ecraser si existe
if(cr != 0)
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, cr);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "deleteEnv", 9) == 0)
else if(modFnIs(e, "deleteEnv", 9))
{
p_etat->error = 0;
// setEnv(nom, valeur, overwritting)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if (!SetEnvironmentVariableA(param1->mPtr, NULL))
{
exc = EXMOD_SYSTEM_SETENV;
setError(p_etat, exc);
}
#else
int cr = unsetenv(param1->mPtr); // suppression
if(cr != 0)
{
exc = EXMOD_SYSTEM_UNSETENV;
setError(p_etat, cr);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getOS", 5) == 0)
else if(modFnIs(e, "getOS", 5))
{
p_etat->error = 0;
// uname() donne les infos
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
dynLet(e, param1, "Windows", DYN_LGNONE);
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
@@ -295,19 +345,63 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
exc = EXMOD_SYSTEM_UNAME;
setError(p_etat, errno);
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getHostname", 5) == 0)
else if(modFnIs(e, "getHostname", 11))
{
// TODO dans sockMod !!
p_etat->error = 0;
// uname() donne les infos
if(param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
DWORD size = param1->mLgmax;
if (!GetComputerNameA(param1->mPtr, &size))
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
if (gethostname(param2->mPtr, param2->mLgmax) == SOCKET_ERROR)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
struct hostent * host_entry;
host_entry = gethostbyname(param2->mPtr);
if (host_entry == NULL)
{
WSACleanup();
exc = EXMOD_SYSTEM_GETHOST;
setError(p_etat, errno);
}
else
{
dynLet(e, param2, inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]), DYN_LGNONE);
WSACleanup();
}
}
}
}
#else
struct utsname name;
int lg;
if(uname(&name) == 0)
@@ -335,11 +429,13 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
setError(p_etat, errno);
exc = EXMOD_SYSTEM_UNAME;
}
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "fork", 4) == 0)
else if(modFnIs(e, "fork", 4))
{
// TODO a supprimer, cf. processMod
p_etat->error = 0;
#ifndef UNIX
// faire differemment sous windows : pas de fork dispo ? CreateProcess()
@@ -360,8 +456,9 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "wait", 4) == 0)
else if(modFnIs(e, "wait", 4))
{
// TODO a supprimer, cf. processMod
#ifndef UNIX
// faire differemment sous windows : pas de wait dispo ? WaitForSingleObject()
#else
@@ -371,25 +468,78 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
#endif
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "kill", 4) == 0)
else if(modFnIs(e, "sendSignal", 10))
{
#ifndef UNIX
// faire differemment sous windows : pas de kill dispo ?
#else
kill(0, SIGTERM); // envoi un signal de fin a tous les fils
#endif
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else
{
number pid, numSignal;
if( var_conv_num(e,param1, &pid) && var_conv_num(e, param2, &numSignal) )
{
pid /= NUM_FACTEUR;
numSignal /= NUM_FACTEUR;
#ifdef WINLIB
// faire differemment sous windows : pas de kill dispo, passer par des evenements (GenerateConsoleCtrlEvent ne fonctionne pas si autre session/cmd/BACK...)
#define SIGINT 2
#define SIGUSR1 10
#define SIGTERM 15
// autoriser tous les process a inter agir...
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); // NULL => acces total pour tous
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
//
HANDLE hEvent = NULL;
char eventName[40] = {0};
if(numSignal == SIGTERM || numSignal == SIGINT)
{
sprintf(eventName, "Global\\wterm%lld", pid);
hEvent= CreateEvent(&sa, FALSE, FALSE, eventName);
}
else if(numSignal == SIGUSR1)
{
sprintf(eventName, "Global\\wdebug%lld", pid);
hEvent = CreateEvent(&sa, FALSE, FALSE, eventName);
}
if(hEvent != NULL) // GetLastError() == ERROR_ALREADY_EXISTS n'est pas une erreur : l'event existe deja (et hEvent n'est pas NULL)
{
// envoyer le signal
SetEvent(hEvent);
CloseHandle(hEvent);
}
//
#else
if(numSignal == SIGTERM || numSignal == SIGINT || numSignal == SIGUSR1)
kill(pid, numSignal);
#endif
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "sleep", 5) == 0)
else if(modFnIs(e, "sleep", 5))
{
#ifndef UNIX
// faire differemment sous windows : pas de sleep dispo ?
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
// 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
+158
View File
@@ -0,0 +1,158 @@
/* **********************************************
__ __ __
\ \/ \/ / 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;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
/* here */
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
if(p_etat != NULL)
{
/* here */
}
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
/* ============================================================================================= */
else if(modFnIs(e, "xxx", 3))
{
/* sample */
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC && param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
number x;
if(var_conv_num(e, param1, &x))
exc = EXMOD_xxx;
else
exc = OK;
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
}
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;
}
+30 -26
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024 lanisys.fr
\/ \/ Copyright 2024,2025 lanisys.fr
This file is part of W language.
@@ -20,6 +20,9 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#ifdef WINLIB
#include "windows.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
@@ -48,11 +51,13 @@ typedef struct {
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_GETCLOCK 1
#define EXMOD_PARAMNUM 2
#define EXMOD_FORMAT_KO 3
#define EXMOD_JETLAG_KO 4
#define EXMOD_DURATION_GETCLOCK 5
enum {
EXMOD_GETCLOCK = 1,
EXMOD_PARAMNUM = 2,
EXMOD_FORMAT_KO = 3,
EXMOD_JETLAG_KO = 4,
EXMOD_DURATION_GETCLOCK = 5
};
static int setError(modEtat * p, int err)
{
@@ -297,13 +302,12 @@ static void FormatTm(env * e, modEtat * p_etat, const char * format, time_t dhm,
}
/* fonctions locales au module FIN */
#ifndef UNIX
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
extern long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#endif
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
@@ -326,7 +330,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(strncmp(e->fn, "init", 4) == 0)
if(modFnIs(e, "init", 4))
{
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
@@ -343,7 +347,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
dynInit(e, &p_etat->valNum, DYN_LGMIN);
}
}
else if(strncmp(e->fn, "end", 3) == 0)
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
if(p_etat != NULL)
@@ -352,7 +356,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
dynFree(e, &p_etat->horodate);
dynFree(e, &p_etat->valNum);
}
else if(strncmp(e->fn, "vers", 4) == 0)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1 == NULL)
@@ -364,7 +368,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
else if(strncmp(e->fn, "error", 5) == 0)
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
@@ -380,7 +384,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ============================================================================================= */
else if(strncmp(e->fn, "startChrono", 11) == 0)
else if(modFnIs(e, "startChrono", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -398,7 +402,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "lapChrono", 9) == 0)
else if(modFnIs(e, "lapChrono", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -417,7 +421,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setUTC", 6) == 0)
else if(modFnIs(e, "setUTC", 6))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -445,7 +449,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setLocal", 8) == 0)
else if(modFnIs(e, "setLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -480,7 +484,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setNowLocal", 11) == 0)
else if(modFnIs(e, "setNowLocal", 11))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -508,7 +512,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "setNowUTC", 9) == 0)
else if(modFnIs(e, "setNowUTC", 9))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -530,7 +534,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "set", 3) == 0)
else if(modFnIs(e, "set", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -563,7 +567,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getUTC", 6) == 0)
else if(modFnIs(e, "getUTC", 6))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -583,7 +587,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "getLocal", 8) == 0)
else if(modFnIs(e, "getLocal", 8))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -609,7 +613,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "get", 3) == 0)
else if(modFnIs(e, "get", 3))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -632,7 +636,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "alarmUTCHM", 16) == 0)
else if(modFnIs(e, "alarmUTCHM", 10))
{
if(p_etat == NULL)
exc = EX_MODETAT;
@@ -670,7 +674,7 @@ extern long execModule(env * e, var * param1, var * param2, var * param3, void *
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(strncmp(e->fn, "alarmLocalHM", 18) == 0)
else if(modFnIs(e, "alarmLocalHM", 12))
{
if(p_etat == NULL)
exc = EX_MODETAT;
+148 -19
View File
@@ -29,7 +29,16 @@
#include "var.h"
#include "hashtable.h"
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf)
{
/* ne pas regarder le type precedent : ecraser ! */
if(v == NULL)
@@ -55,15 +64,19 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
v->lg = 0;
v->lgmax = sep_lgm;
v->ptr[0] = 0;
v->codePage = WCP_DEFAULT;
}
break;
case VAR_BUFFER:
if(sep_lgm < BUF_LGBLOC)
sep_lgm = BUF_LGBLOC;
if(sep_lgm < BUF_LGMINBLOC)
sep_lgm = BUF_LGMINBLOC;
else if((sep_lgm % 32) != 0)
sep_lgm = ((sep_lgm / 32) + 1) * 32; // taille multiple de 32, sinon pile d'elements de 8 et 16 ko !!
if((v->ptr = memalloc(e, sep_lgm)) == NULL)
v->type = VAR_NULL; /* exception levee dans memalloc */
else
{
memset(v->ptr, 0, sep_lgm);
v->lgmax = sep_lgm;
v->read = 0;
v->write = 0;
@@ -98,23 +111,129 @@ void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeu
}
}
void var_ctrl_param(env * e, var * v)
WAPIDECL int varptrtbl_ctrl(env * e, var * v)
{
/* controle que la var "v", si de type PARAM, pointe sur une var toujours existante... */
if(v->type != VAR_PARAM)
return;
/* TODO lire e->par_ptr de type dynamic ??? */
/* dans le cas : hash, puis var de hash, puis clear hash : quid de la var de hash : ras car c'est une copie ! */
/* indique si la var "v" appartient a une var de type pointeur (TRUE) */
if(v == NULL)
return FALSE;
if(v->type == VAR_PARAM)
return FALSE;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad var param, v[3] = ptr de la var param, v[4] = ad var param2, etc.
*/
pointeur * beg = (pointeur *)e->varptrtbl.ptr;
ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
pointeur * curr = beg + 2;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v->ptr)
return TRUE; // deja existant
else
curr += 2;
// pas trouve
return FALSE;
}
void var_free(env * e, var * v, int suivre_par)
WAPIDECL void varptrtbl_maj(env * e, var * v)
{
// ajoute a e->varptrtbl la var si de type "pointeur" : VAR_PARAM, objet...
if(v == NULL)
return;
if(v->type != VAR_PARAM)
return;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad var param, v[3] = ptr de la var param, v[4] = ad var param2, etc.
*/
pointeur * beg = (pointeur *)e->varptrtbl.ptr;
ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
pointeur * curr = ++beg;
ent64 addnb = nb + 1;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v)
{
curr++;
*curr = (pointeur)v->ptr;
return; // deja existant : maj ptr vraie var
}
else
curr += 2;
// pas trouve : ajout a la fin
if(dynCtrl(e, &e->varptrtbl, sizeof(pointeur) * addnb * 2 + 1, TRUE))
{
beg = (pointeur *)e->varptrtbl.ptr; // au cas ou realloc memoire
*((ent64 *)beg) = addnb;
curr = beg + addnb * 2;
*curr-- = (pointeur)v->ptr;
*curr = (pointeur)v;
}
}
WAPIDECL void varptrtbl_del(env * e, var * v)
{
// supprime de e->varptrtbl la var param v
if(v == NULL)
return;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad ptr, v[3] = ptr sur la var param, v[4] = ad ptr 2, etc.
*/
pointeur * beg = (pointeur *)e->varptrtbl.ptr;
ent64 nb = *((ent64 *)beg); // ok si sizeof(pointeur) = sizeof(ent64)
pointeur * curr = ++beg;
ent64 savnb = nb;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v)
{
// trouve : mettre le dernier a la place de celui en cours, sauf si c'est le dernier
*((ent64 *)beg) = savnb - 1;
if(nb > 0) // pas de swap a faire si c'est le dernier qui est supprime
{
beg += savnb * 2 - 1; // le dernier
*curr++ = *beg++;
*curr = *beg;
}
}
else
curr += 2;
// pas trouve : RAS
}
WAPIDECL int var_conv_num(env * e, var * v, number * num)
{
if(v == 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);
}
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)
{
@@ -145,15 +264,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
@@ -169,7 +300,6 @@ void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
case VAR_DYNAMIC:
var_init(e, let, v->type, 0, v->lg + 1, NULL); // +1 pour le \0 de fin
memcopie(let->ptr, v->ptr, v->lg + 1); // permet de copier le \0 de fin
//memcpy(let->ptr, v->ptr, v->lg + 1);
let->lg = v->lg;
break;
//
@@ -179,12 +309,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;
+10 -4
View File
@@ -23,10 +23,16 @@
#ifndef VAR_H
#define VAR_H
void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
void var_ctrl_param(env * e, var * v);
void var_free(env * e, var * v, int suivre_par);
void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
#include "apidecl.h"
WAPIDECL void var_init(env * e, var * v, octet type, ent64 mod_lg, ent64 sep_lgm, pointeur pf);
WAPIDECL int var_conv_num(env * e, var * v, number * num);
WAPIDECL void var_free(env * e, var * v, int suivre_par);
WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v);
WAPIDECL int varptrtbl_ctrl(env * e, var * v);
WAPIDECL void varptrtbl_maj(env * e, var * v);
WAPIDECL void varptrtbl_del(env * e, var * v);
/* ********************************************** */
#endif
+18
View File
@@ -0,0 +1,18 @@
set WBIN=exec
set WLIB=.
set WSRC=.
exec\lwc prg.w
exec\lwa prg.wa
exec\lw prg
rem
exec\lwc comp.w
exec\lwa comp.wa
exec\lw comp
rem
exec\lwc pdf.w
exec\lwa pdf.wa
exec\lw pdf
rem
exec\lwc debug.w
exec\lwa debug.wa
exec\lw debug 1234
+131
View File
@@ -0,0 +1,131 @@
; regles lex des token w
; \r est supprime des lignes et \n sert de separateur de lignes : non present
blank: (1,*,#20#09)
comment: (1,1,#3B) (0,*,#00-#FF)
begin: begin
background: background
library: library
end: end
except: except
throw: throw
catch: catch
include: include
sub: sub
endsub: endsub
if: if
then: then
else: else
elseif: elseif
endif: endif
do: do
call: call
invoke: invoke
return: return
returnon: returnon
loop: loop
endloop: endloop
foreach: foreach
in: in
like: like
endfor: endfor
break: break
breakon: breakon
continue: continue
continueon: continueon
nop: nop
part: part
echonl: echonl
echo: echo
input: input
declare: declare
let: let
delet: delet
new: new
class: class
this: this
parent: parent
hold: hold
precision: precision
setsep: setsep
int: int
frac: frac
abs: abs
neg: neg
round: round
sqrt: sqrt
exp: exp
type: type
len: len
count: count
dcount: dcount
field: field
index: index
search: search
sortedsearch: sortedsearch
change: change
format: format
insert: insert
remove: remove ; delete (dynamic)
tonum: tonum
tostring: tostring
equal: =
diff: (1,1,#23) ; #
gt: >
lt: <
gte: >=
lte: <=
and: and
or: or
not: not
beginpar: (1,1,#28) ; (
endpar: (1,1,#29) ; )
beginh: (1,1,#7B) ; {
endh: (1,1,#7D) ; }
begins: (1,1,#5B) ; [
ends: (1,1,#5D) ; ]
indirect: !
typeof: typeof ; 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
ident: (1,1,a-zA-Z) (0,23,a-zA-Z0-9)
varsys: @ (1,*,a-z)
numberdec: (1,13,0-9) . (0,5,0-9)
numberint: (1,13,0-9)
minus: (1,1,#2D) ; -
plus: (1,1,#2B) ; +
multiply: (1,1,#2A) ; *
divide: (1,1,#2F) ; /
divident: (1,1,#5C) ; \
modulo: (1,1,#25) ; %
concat: (1,1,#3A) ; :
listesep: (1,1,#2C) ; ,
identsep: (1,1,#2E) ; .
modsep: &
other: (1,1,#00-#FF)
; fin des regles w.lex
+115
View File
@@ -0,0 +1,115 @@
<?php
/*************************************************************************************
* w.php
* -----
* Author: FDE
* Contributors:
* Copyright: (c) 2023
* Release Version: 1.0
* Date Started: 05/10/2024
*
* W language file for GeSHi.
*
* a mettre ici : /lamp0/web/vhosts/www.lanisys.fr/htdocs/wiki/vendor/geshi/geshi/src/geshi
*
*************************************************************************************
*
* This file is part of GeSHi.
*
* GeSHi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GeSHi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GeSHi; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
************************************************************************************/
$language_data = array (
'LANG_NAME' => 'W',
'COMMENT_SINGLE' => array(1 => ';'),
'COMMENT_MULTI' => array(),
'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE,
'QUOTEMARKS' => array('"', '\''),
'ESCAPE_CHAR' => '',
'KEYWORDS' => array(
1 => array(
'begin', 'background', 'library', 'except', 'end', 'sub',
'endsub', 'include', 'loop', 'endloop', 'return', 'returnon',
'break', 'breakon', 'continue', 'continueon', 'throw', 'catch',
'foreach', 'in', 'like', 'if', 'then', 'elseif', 'else',
'endif', 'endfor','echo', 'echonl', 'input', 'nop', 'part', 'declare',
'let', 'do', 'call', 'invoke', 'delet', 'class', 'free',
'new', 'this', 'parent', 'precision', 'setsep'
),
2 => array(
'or', 'and', 'not', 'int', 'frac', 'abs', 'neg', 'type', 'typeof',
'tonum', 'tostring', 'count', 'len', 'format', 'dcount',
'round', 'field', 'index', 'search', 'change', 'insert', 'remove'
)
),
'SYMBOLS' => array(
'(', ')', '{', '}', '[', ']'
),
'CASE_SENSITIVE' => array(
GESHI_COMMENTS => false,
1 => true,
2 => true,
),
'STYLES' => array(
'KEYWORDS' => array(
1 => 'color: #b1b100; font-weight: bold;',
2 => 'color: #b1b100;'
),
'COMMENTS' => array(
1 => 'color: #666666; font-style: italic;',
),
'ESCAPE_CHAR' => array(
0 => 'color: #000099; font-weight: bold;'
),
'BRACKETS' => array(
0 => 'color: #000066;'
),
'STRINGS' => array(
0 => 'color: #009900;'
),
'NUMBERS' => array(
0 => 'color: #CC0000;'
),
'METHODS' => array(
1 => 'color: #006600;'
),
'SYMBOLS' => array(
0 => 'color: #000066;'
),
'REGEXPS' => array(
),
'SCRIPT' => array(
0 => '',
1 => '',
)
),
'URLS' => array(
1 => '',
2 => ''
),
'OOLANG' => false,
'OBJECT_SPLITTERS' => array(
1 => '\\'
),
'REGEXPS' => array(
),
'STRICT_MODE_APPLIES' => GESHI_NEVER,
'SCRIPT_DELIMITERS' => array(),
'HIGHLIGHT_STRICT_BLOCK' => array(
0 => false,
1 => false
)
);
+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;
}
+103
View File
@@ -0,0 +1,103 @@
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
1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64
1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79
1,1,65;1,1,6E;1,1,64
1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74
1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77
1,1,63;1,1,61;1,1,74;1,1,63;1,1,68
1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65
1,1,73;1,1,75;1,1,62
1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62
1,1,69;1,1,66
1,1,74;1,1,68;1,1,65;1,1,6E
1,1,65;1,1,6C;1,1,73;1,1,65
1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66
1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66
1,1,64;1,1,6F
1,1,63;1,1,61;1,1,6C;1,1,6C
1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65
1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E
1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E
1,1,6C;1,1,6F;1,1,6F;1,1,70
1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70
1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68
1,1,69;1,1,6E
1,1,6C;1,1,69;1,1,6B;1,1,65
1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72
1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B
1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E
1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65
1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E
1,1,6E;1,1,6F;1,1,70
1,1,70;1,1,61;1,1,72;1,1,74
1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C
1,1,65;1,1,63;1,1,68;1,1,6F
1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74
1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65
1,1,6C;1,1,65;1,1,74
1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74
1,1,6E;1,1,65;1,1,77
1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73
1,1,74;1,1,68;1,1,69;1,1,73
1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74
1,1,68;1,1,6F;1,1,6C;1,1,64
1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E
1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70
1,1,69;1,1,6E;1,1,74
1,1,66;1,1,72;1,1,61;1,1,63
1,1,61;1,1,62;1,1,73
1,1,6E;1,1,65;1,1,67
1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64
1,1,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
1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74
1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64
1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78
1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68
1,1,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
1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65
1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D
1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67
1,1,3D
1,1,23
1,1,3E
1,1,3C
1,1,3E;1,1,3D
1,1,3C;1,1,3D
1,1,61;1,1,6E;1,1,64
1,1,6F;1,1,72
1,1,6E;1,1,6F;1,1,74
1,1,28
1,1,29
1,1,7B
1,1,7D
1,1,5B
1,1,5D
1,1,21
1,1,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
1,1,40;1,-1,61-7A
1,13,30-39;1,1,2E;0,5,30-39
1,13,30-39
1,1,2D
1,1,2B
1,1,2A
1,1,2F
1,1,5C
1,1,25
1,1,3A
1,1,2C
1,1,2E
1,1,26
1,1,00-FF