Author SHA1 Message Date
fred b6bea78591 feat: release alpha-8 2026-07-14 10:19:52 +02:00
fred 0445f10ebe WIP VAR_PARAM management 2026-06-28 18:01:09 +02:00
fred ad317a2070 feat: ssh_lib, VAR_PARAM management (when hashtable element) 2026-06-28 16:12:04 +02:00
fred e0eaf6f9e8 WIP exception bubbling 2026-06-14 18:14:25 +02:00
fred b70cee802b WIP exception bubbling
WIP ssh lib
2026-06-14 15:45:35 +02:00
fred 84bdea04ea WIP setup for secure socket (openSSL)
fix: cipher lib
2026-06-07 18:26:38 +02:00
fred 747c9819f1 feat: cipher aes128 finalized, aes192 & aes256 to test 2026-05-30 18:58:54 +02:00
fred 44b447e9af feat: hash mod, websocket mod, cipher mod 2026-05-30 17:15:23 +02:00
fred 760020f30e WIP socket, sqlite, createprocess 2026-04-25 19:39:08 +02:00
fred 3f4f548e55 WIP socket module 2026-04-25 15:30:48 +02:00
fred 4c80dff382 WIP linux/windows socket 2026-04-12 18:00:39 +02:00
fred 632df00f8d WIP pdf, socket 2026-04-11 18:17:31 +02:00
fred 667531bee8 WIP 2026-04-08 21:31:51 +02:00
fred 0ec33cbe5a WIP sockMod 2026-04-04 20:29:01 +02:00
fred efbd77e7fb WIP http, sock, template 2026-04-04 18:54:42 +02:00
fred 89dcd0b594 WIP http fcgi 2026-04-04 15:40:08 +02:00
fred 3b68b7d408 WIP http fastcgi 2026-03-31 20:56:49 +02:00
fred e39c18d606 WIP VAR_PARAM management
deat: fcgi_lib
2026-03-29 19:57:17 +02:00
fred fc29d78e57 feat: add rename/remove/append to fileMod + error code 2026-03-28 21:25:58 +01:00
fred cb12b9d54f WIP var_param management 2026-03-28 20:59:27 +01:00
fred bcd62e6913 WIP dynamic convert 2026-03-27 13:52:04 +01:00
fred 89a3c4d5c2 fix: except when returning from LIBR / SUB 2026-03-21 20:55:32 +01:00
fred 103ad22814 feat: add sqrt and exp functions 2026-03-21 19:17:26 +01:00
fred c69d94e6c8 feat: compressed wp programs (assembler and runtime) 2026-03-21 14:50:57 +01:00
fred f994cc8188 fix: DEXV/DEXH/DEXI from number to dynamic
feat: lexMod getToken function
test program calc.w
2026-03-20 20:47:48 +01:00
fred e87d3f9237 feat: convMod (renaming encod_lib), add @variables
fix: lexMod, abs() usage in runtime
feat: dynamic new function (not used yet)
WIP sqrt and exp function in runtime, to do instruction compilation
feat: first real w prog (calculator RPN)
2026-03-20 17:39:44 +01:00
fred 0f55fc23f3 feat: alpha-6, lots of feat and fix 2026-03-15 10:29:17 +01:00
fred fa533a0a2d fix: debug exception display 2026-03-08 18:31:01 +01:00
fred 5ddbd73146 fix: string #hexa escaping, debug local variables, SUBR updated si offset
feat: gened.w test program
2026-03-08 12:11:44 +01:00
fred 80847f4993 feat: lex mod, sortedsearch function
fix: dynIns bug (value in empty attribute), typeof mode
WIP varptrtbl
2026-03-07 18:26:27 +01:00
70 changed files with 292723 additions and 2673 deletions

No files matched your search

+12 -5
View File
@@ -1,7 +1,8 @@
#define ARG_DEBUG "d"
#define ARG_TRACE "t"
#define ARG_DISASM "d"
#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)
{
@@ -16,6 +17,11 @@ void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_DEBUG, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_TRACE) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_TRACE, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_DISASM) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_DISASM, 1, cFM, cVM);
else if(strcmp(argv[a], "-" ARG_COMPRESS) == 0)
dynStoreSz(e, arg, 1, ++nbOpt, ARG_COMPRESS, 1, cFM, cVM);
//
else if(strncmp(argv[a], "-WBIN:", 6) == 0 && strlen(argv[a]) > 6)
dynStoreSz(e, arg, 3, DYN_NONE, &argv[a][6], DYN_LGNONE, cFM, DYN_NONE); // memo (.o .so)
else if(strncmp(argv[a], "-WLIB:", 6) == 0 && strlen(argv[a]) > 6)
@@ -27,6 +33,7 @@ void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
else
{
// premier argument ne commencant pas par "-" : nom du prog wp
dynDel(e, arg, 6, clc, cFM, cVM, 1);
for( ; a < argc; a++)
dynStoreSz(e, arg, 2, ++cpt, argv[a], DYN_LGNONE, cFM, cVM);
break;
@@ -45,8 +52,8 @@ void GetArgs(env * e, int argc, char * argv[], Dynamic * arg)
if(dynExtractPos(e, arg, 4, DYN_NONE, cFM, DYN_NONE) <= 0)
dynStoreSz(e, arg, 4, DYN_NONE, getenv("WSRC"), DYN_LGNONE, cFM, DYN_NONE); // si absent en ligne de cmd, lire de la var d'env
/*
arg<1> = options en MV
arg<2> = prog et parametres en MV
arg<1> = options de lw en MV
arg<2> = prog w et ses parametres en MV
arg<3> = WBIN (.o .so) => invoke, LD_LIBRARY_PATH
arg<4> = WSRC (.w) => lwc
arg<5> = WLIB (.wp .wa) => call, lwa lwc
+51 -103
View File
@@ -32,6 +32,7 @@
#include "dynamic.h"
#include "instr.h"
#include "arg.c"
#include "lzw.h"
env e;
@@ -47,12 +48,16 @@ env e;
int subNiv;
Dynamic adrLabel;
/*
adrLabel<1> = label, adrLabel<2> = offset (adresse) du label
adrLabel<1> = label
adrLabel<2> = offset (adresse) du label
adrLabel<3, subNiv> = ad debut sub en cours (debut PROG/SUBR)
adrLabel<4> = liste labels dans des JUMP a completer
adrLabel<5> = liste de la position du JUMP ou ecrire l'offset (adresse) du label
*/
/* contexte pour lzw */
modContextLzw ctxCompress;
/* -------------------- */
ent64 lap = 0; /* calcul temps du programme (hors init, alloc et free), en ms */
@@ -82,8 +87,10 @@ void decodeString(env * e, Dynamic * this)
{
/* TODO ! voir avec le compilateur s'il ne fait pas deja le travail */
/* genw remplace " par #22 et ' ' par #20 : on fait l'inverse ici */
dynChange(e, this, "#22", "\"", DYN_ALL);
dynChange(e, this, "#20", " ", DYN_ALL);
/* + pbm #0A qui saute une ligen et ok ici ... */
//dynChange(e, this, "#22", "\"", DYN_ALL);
//dynChange(e, this, "#20", " ", DYN_ALL);
dynCleanHexaMark(e, this);
}
Dynamic pcode;
@@ -99,7 +106,7 @@ void PCODEP(int x)
pcode.ptr[posOffset++]=((octet)x);
}
int assembler(env * e, char * fichier, int * cptLig)
int assembler(env * e, char * fichier, int * cptLig, int compress)
{
//#define PCODE(x) {dynConcatSz(e,&pcode,"0",1);pcode.ptr[pcode.mLg-1]=((octet)x);}
//#define PCODEP(x) pcode.ptr[pcode.mLg++]=((octet)x);
@@ -244,7 +251,7 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &adrLabel, &trav, 3, subNiv, cFM, cVM, 1); // adresse debut sub en cours
debutSub = dynToNum(e, &trav, DYN_FALSE, 8);
if(subNiv > 1)
debutSub = debutSub + 2 + pcode.ptr[debutSub + 1];
debutSub = debutSub + 2 + 3 + 1 + pcode.ptr[debutSub + 1]; // se mettre APRES l'instruction SUBR/PHDS/PIDS (5 + lg et le 1 pour annuler le +1 qui est apres...)
offset = offset + 1 - debutSub; // ad debut loop - debut du prog/sub en cours
PCODE((offset >> 16) & 255); // 23/11/2025 - verif PCODE ok a la place de PCODEP
PCODE((offset >> 8 ) & 255); // 23/11/2025 - verif PCODE ok a la place de PCODEP
@@ -292,7 +299,7 @@ int assembler(env * e, char * fichier, int * cptLig)
dynField(e, &ligne, &tmp, i++, 0, ' ', 0, 1);
if(tmp.mLg < 1 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom variable
num = tmp.mLg;
if(num == 1 && tmp.mPtr[0] == '_') // assembler SUBR _ pour avoir lg = 0
if(num == 1 && tmp.mPtr[0] == '_') // assembler SUBR _ pour avoir lg = 0 (?? A GARDER ?? FDE 08/03/2026)
num = 0;
PCODE(instr);
PCODE(num);
@@ -407,6 +414,7 @@ int assembler(env * e, char * fichier, int * cptLig)
case IN_SELE:
case IN_RNXT:
case IN_CPHA:
case IN_CPHH:
// PVAT / TYPO / PSHT / SELE / RNXT / CPHA
PCODE(instr);
break;
@@ -468,87 +476,50 @@ int assembler(env * e, char * fichier, int * cptLig)
ret = -9; // code comparaison inconnu
break;
case IN_ADDN:
// ADDN
case IN_SBCN:
// SBCN
case IN_MULN:
// MULN
case IN_DIVN:
// DIVN
case IN_DIVE:
// DIVE
case IN_MODN:
// MODN
case IN_INTE:
// INTE
case IN_FRAC:
// FRAC
case IN_NEGN:
// NEGN
case IN_ABSN:
// ABSN
case IN_SQRT:
case IN_IEXP:
case IN_DTON:
// DTON
case IN_NTOD:
// NTOD
case IN_HLET:
// HLET
case IN_CCAT:
// CCAT
case IN_ROUN:
// ROUN
case IN_TYPE:
// TYPE
case IN_LENG:
// LENG
case IN_COUN:
// COUN
case IN_DCOF:
// DCOF
case IN_DCOS:
// DCOS
case IN_INDX:
// INDX
case IN_FIEL:
// FIEL
case IN_FLDF:
// FLDF
case IN_FLDS:
// FLDS
case IN_SSTR:
// SSTR
case IN_SSEP:
// SSEP
case IN_FMTA:
// FMTA
case IN_FMTT:
// FMTT
case IN_FMTS:
// FMTS
case IN_SRCH:
// SRCH
case IN_SCHS:
// SCHS
case IN_SSRC:
case IN_SSCS:
case IN_CHNG:
// CHNG
case IN_INSE:
// INSE
case IN_INSS:
// INSS
case IN_REMV:
// REMV
case IN_REMS:
// REMS
case IN_TONU:
// TONU
case IN_TOST:
// TOST
case IN_DEXV:
// DEXV
case IN_DESV:
// DESV
case IN_DEZV:
// DEZV
case IN_SADV:
case IN_VLET:
case IN_HCOU:
@@ -615,7 +586,7 @@ int assembler(env * e, char * fichier, int * cptLig)
PCODE(num);
break;
case IN_DSET:
// DSET - TODO decoder la chaine, cas des \xx en hexa (recalcul lg : fn qui met a jour directement tmp et maj lg)
// DSET - TODO decoder la chaine, cas des #xx en hexa (recalcul lg : fn qui met a jour directement tmp et maj lg)
dynField(e, &ligne, &tmp, 2, 0, '"', 0, 1);
decodeString(e, &tmp);
if(tmp.mLg < 0 || tmp.mLg > 255) { ret = -4; break; } // erreur longueur nom
@@ -736,10 +707,6 @@ int assembler(env * e, char * fichier, int * cptLig)
for(int p = 0; p < num; p++)
PCODE(tmp.mPtr[p]);
break;
case IN_TEST:
// TEST
PCODE(instr);
break;
case IN_ENDL:
case IN_ENDP:
// ENDL / ENDP : fin de librairie / prog directement executable
@@ -774,6 +741,14 @@ int assembler(env * e, char * fichier, int * cptLig)
// si pas d'erreur, ecrire au meme endroit que le .wa (=> dans WLIB)
dynLet(e, &tmp, fichier, DYN_LGNONE);
tmp.mPtr[tmp.mLg - 1] = 'p';
if(compress)
{
/* compression lzw avant */
initLzw(e, &ctxCompress);
if(setLzw(e, &pcode, &ctxCompress, 0) != OK)
printf("Erreur de compression Lzw du binaire wp - ecriture en clair\n");
freeLzw(e, &ctxCompress);
}
dynWrite(e, &pcode, tmp.mPtr);
}
//
@@ -809,6 +784,19 @@ int disassembler(env * e, char * fichier)
dynFree(e, &pcode);
return -1;
}
/* si bit 7 premier octet = 0 => compresse */
if(pcode.ptr[0] < 128)
{
/* decompression lzw avant */
initLzw(e, &ctxCompress);
if(getLzw(e, &pcode, &ctxCompress, 0) != OK)
{
printf("Erreur de decompression Lzw du binaire wp \n");
dynFree(e, &pcode);
return -1;
}
freeLzw(e, &ctxCompress);
}
dynInit(e, &tmp, DYN_LGMIN);
dynInit(e, &varsys, DYN_LGMIN);
dynInit(e, &niv, DYN_LGMIN);
@@ -993,87 +981,50 @@ int disassembler(env * e, char * fichier)
dumpHex(&pcode, si_instr, si);
break;
case IN_ADDN:
// ADDN
case IN_SBCN:
// SBCN
case IN_MULN:
// MULN
case IN_DIVN:
// DIVN
case IN_DIVE:
// DIVE
case IN_MODN:
// MODN
case IN_INTE:
// INTE
case IN_FRAC:
// FRAC
case IN_NEGN:
// NEGN
case IN_ABSN:
// ABSN
case IN_SQRT:
case IN_IEXP:
case IN_DTON:
// DTON
case IN_NTOD:
// NTOD
case IN_HLET:
// HLET
case IN_CCAT:
// CCAT
case IN_ROUN:
// ROUN
case IN_TYPE:
// TYPE
case IN_LENG:
// LENG
case IN_COUN:
// COUN
case IN_DCOF:
// DCOF
case IN_DCOS:
// DCOS
case IN_INDX:
// INDX
case IN_FIEL:
// FIEL
case IN_FLDF:
// FLDF
case IN_FLDS:
// FLDS
case IN_SSTR:
// SSTR
case IN_SSEP:
// SSEP
case IN_FMTA:
// FMTA
case IN_FMTT:
// FMTT
case IN_FMTS:
// FMTS
case IN_SRCH:
// SRCH
case IN_SCHS:
// SCHS
case IN_SSRC:
case IN_SSCS:
case IN_CHNG:
// CHNG
case IN_INSE:
// INSE
case IN_INSS:
// INSS
case IN_REMV:
// REMV
case IN_REMS:
// REMS
case IN_TONU:
// TONU
case IN_TOST:
// TOST
case IN_DEXV:
// DEXV
case IN_DESV:
// DESV
case IN_DEZV:
// DEZV
case IN_SADV:
case IN_VLET:
case IN_HCOU:
@@ -1136,6 +1087,8 @@ int disassembler(env * e, char * fichier)
// RNXT
case IN_CPHA:
// CPHA
case IN_CPHH:
// CPHJ
case IN_PSHV:
// PSHV
case IN_POPV:
@@ -1240,12 +1193,6 @@ int disassembler(env * e, char * fichier)
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_TEST:
// TEST
si++;
printf("\n");
dumpHex(&pcode, si_instr, si);
break;
case IN_ENDS:
// ENDS
si++;
@@ -1283,10 +1230,10 @@ int main(int argc, char * argv[])
/* avis de licence */
printf("W language Copyright 2024,2025 lanisys.fr\n");
printf("This program comes with ABSOLUTELY NO WARRANTY;\nThis is free software, and you are welcome to redistribute it\nunder certain conditions (GPL-3.0-or-later)\n\n");
/* argument : fichier a assembler/desassembler (si -d) */
/* argument : fichier a assembler/desassembler (si -d), assembler avec compression lzw (si -c) */
if(argc < 2)
{
printf("Usage: lwa [-d] [-WLIB:<chemin>] <fichier.wa|fichier.wp>\n");
printf("Usage: lwa [-c|-u] [-WLIB:<chemin>] <fichier.wa|fichier.wp>\n");
exit(-1);
}
/* */
@@ -1329,11 +1276,12 @@ int main(int argc, char * argv[])
}
else
{
int compress = dynLocateSz(&e, &arg, ARG_COMPRESS, cVM, 1, cFM);
int numLig = 0;
#ifndef UNIX
if((cr = assembler(&e, wlib.mPtr, &numLig)) != OK)
if((cr = assembler(&e, wlib.mPtr, &numLig, compress)) != OK)
#else
if((cr = assembler(&e, wlib.mPtr, &numLig)) != OK)
if((cr = assembler(&e, wlib.mPtr, &numLig, compress)) != OK)
#endif
{
printf("Erreur %d a la ligne %d\n", cr, numLig);
+17 -11
View File
@@ -76,9 +76,16 @@ WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
return;
if(varbuf->type != VAR_BUFFER)
return;
/* uniquement lecture dans VAR_DYNAMIC : raz var sinon */
/* */
if(v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* uniquement lecture dans VAR_DYNAMIC : raz var sinon */
if(v->type != VAR_DYNAMIC)
{
var_free(e, v, TRUE);
@@ -108,7 +115,6 @@ WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
{
/* copier un seul bloc */
memcopie(v->ptr, BUFPTR(varbuf) + p, lg);
//memcpy(v->ptr, varbuf->ptr + p, lg);
v->lg = lg;
*(v->ptr + lg) = 0; /* \0 de fin de chaine */
if(p + lg >= varbuf->lgmax)
@@ -120,9 +126,7 @@ WAPIDECL void buffer_read(env * e, var * varbuf, var * v)
{
/* 2 blocs */
memcopie(v->ptr, BUFPTR(varbuf) + p, lgfin);
//memcpy(v->ptr, varbuf->ptr + p, lgfin);
memcopie(v->ptr + lgfin, BUFPTR(varbuf), lg - lgfin);
//memcpy(v->ptr + lgfin, varbuf->ptr, lg - lgfin);
varbuf->read = lg - lgfin;
}
}
@@ -136,10 +140,16 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
if(varbuf == NULL || v == NULL)
return;
if(v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* uniquement ecriture d'une VAR_DYNAMIC */
if(varbuf->type != VAR_BUFFER || v->type != VAR_DYNAMIC)
return;
/* uniquement ecriture d'une VAR_DYNAMIC */
if(v->lg > (varbuf->lgmax / 2)) // pour pouvoir ecrire au moins 2 items dans le buffer
{
e->exception = EX_BUFOVF; /* trop grand a ecrire */
@@ -161,7 +171,6 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
*(BUFPTR(varbuf) + p) = v->lg & 255;
p++;
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
varbuf->write = p + v->lg;
}
else
@@ -188,7 +197,6 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
{
/* copier en une fois */
memcopie(BUFPTR(varbuf) + p, v->ptr, v->lg);
//memcpy(varbuf->ptr + p, v->ptr, v->lg);
if(p + v->lg >= varbuf->lgmax)
varbuf->write = 0; /* pas plus cas sinon il y aurait eu copie en 2 fois */
else
@@ -198,9 +206,7 @@ WAPIDECL void buffer_write(env * e, var * varbuf, var * v)
{
/* en 2 fois */
memcopie(BUFPTR(varbuf) + p, v->ptr, lgfin);
//memcpy(varbuf->ptr + p, v->ptr, lgfin);
memcopie(BUFPTR(varbuf), v->ptr + lgfin, v->lg - lgfin);
//memcpy(varbuf->ptr, v->ptr + lgfin, v->lg - lgfin);
varbuf->write = v->lg - lgfin;
}
}
+269
View File
@@ -0,0 +1,269 @@
; w faire une calculatrice RPN : nombre, opérateurs + - * / , fonctions neg frac int mod div , commandes : quitter, clear vide pile (utiliser le module lex), dup (duplique dernier elemn pile), pop enleve dernier element, precision
begin
sub displayStack(stack)
declare size, one, minusOne, elem
let size = dcount(stack)
if size = 0 then
echonl "<empty stack>"
return
endif
let one = 1
let minusOne = neg(one)
foreach elem in size, one, minusOne
echonl format(elem, @right, '0', 2):'> ':format(stack{elem}, @right, ' ', 20)
endfor
except
endsub
;
declare rules, crules, Rule ; lex rules and compiled rules, Rule (pour echapper # 2 fois => #23#32#33)
let crules = ''
let rules = 'integer: int '
let rules{2} = 'fractionnal: frac '
let rules{3} = 'absolute: abs '
let rules{4} = 'negation: neg '
let rules{5} = 'round0: round0 '
let rules{6} = 'round1: round1 '
let rules{7} = 'round2: round2 '
let rules{8} = 'round3: round3 '
let rules{9} = 'round4: round4 '
let rules{10} = 'random: rnd ; random '
let rules{11} = 'varsys: @ (1,*,a-z) '
let rules{12} = 'number: (0,1,#23#32#332D) (1,13,0-9) . (0,5,0-9) ' ; corriger le double 'escape' car - est un car reserve lex (- => #2D => #23#32#33#23#33#32#23#34#34) car sinon compil/assembleur decode mal le -
let rules{13} = 'integernumber: (0,1,#23#32#332D) (1,13,0-9) '
let rules{14} = 'minus: (1,1,#23#32#332D) ; - '
let rules{15} = 'plus: (1,1,#2B) ; + '
let rules{16} = 'multiply: (1,1,#2A) ; * '
let rules{17} = 'divide: (1,1,#2F) ; / '
let rules{18} = 'integerdivide: (1,1,#5C) ; \ '
let rules{19} = 'modulus: (1,1,#25) ; % '
let rules{20} = 'quit: quit '
let rules{21} = 'dup: dup '
let rules{22} = 'pop: pop '
let rules{23} = 'clear: clear '
let rules{24} = 'space: (1,1,#23#32#3320) '
let rules{25} = 'other: (1,1,#23#32#3300-#23#32#33FF)'
let rules = change(rules, @fm, @lf)
part 1
let Rule = {}
invoke lex&compile(rules, crules, Rule)
part 2
; todo mettre la sub qui suit dans le module lex (? pbm il faut 4/5 params)
declare tok
let tok = {}
sub getToken(tokenList, tokenIndex, tokenNumber, value)
let tokenNumber = tokenList{2, tokenIndex}
if tokenNumber # '' then
declare hexa
let hexa = ''
let hexa = tokenList{1, tokenIndex}
invoke conv&fromHexa(hexa, value)
endif
; si besoin
invoke lex&getToken(tokenList, tokenIndex, tok)
except
endsub
;
echonl "wcalc => + - * / \ % int frac abs neg rnd round0 round1 round2 round3 round4 @pi pop dup clear quit"
;
declare value, stack, token, ind, ruleNumber, ruleValue
let value = ''
let token = ''
let stack = ''
loop
do displayStack(stack)
echo 'wcalc: '
let value = ''
input value
invoke lex&analyze(crules, value, token)
; -----------------------------------------------
; token{1/2/3} en MV : chaine hexa, no token, ordinal_position
let ind = 0
let ruleValue = ''
let ruleNumber = 0
loop
let ind = ind + 1
do getToken(token, ind, ruleNumber, ruleValue)
breakon ruleNumber = ''
continueon ruleNumber = Rule.space
;
if ruleNumber = Rule.other then
echonl 'Syntax error'
break;
; -----------------------------------------------
elseif ruleNumber = Rule.dup then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack = insert(stack, stack{1}, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.pop then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.clear then
let stack = ''
; -----------------------------------------------
elseif ruleNumber = Rule.number or ruleNumber = Rule.integernumber then
if dcount(stack) > 15 then
echonl "Stack full error"
else
let stack = insert(stack, ruleValue, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.random then
if dcount(stack) > 15 then
echonl "Stack full error"
else
declare rnd
let rnd = 0
invoke random&get(rnd)
let stack = insert(stack, rnd, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.varsys then
if dcount(stack) > 15 then
echonl "Stack full error"
else
if ruleValue = '@pi' then
let stack = insert(stack, @pi, 1)
else
echonl "Unknown constant"
endif
endif
; -----------------------------------------------
elseif ruleNumber = Rule.plus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} + stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.minus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} - stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.divide then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} / stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.integerdivide then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} \ stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.modulus then
if dcount(stack) < 2 then
echonl "Stack underflow error"
elseif stack{1} = 0 then
echonl "Division by zero error"
else
let stack{2} = stack{2} % stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.multiply then
if dcount(stack) < 2 then
echonl "Stack underflow error"
else
let stack{2} = stack{2} * stack{1}
let stack = remove(stack, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.negation then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = neg(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.integer then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = int(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.fractionnal then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = frac(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.absolute then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = abs(stack{1})
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round0 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 0)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round1 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 1)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round2 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 2)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round3 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 3)
endif
; -----------------------------------------------
elseif ruleNumber = Rule.round4 then
if dcount(stack) < 1 then
echonl "Stack underflow error"
else
let stack{1} = round(stack{1}, 4)
endif
endif
; -----------------------------------------------
breakon ruleNumber = Rule.quit
endloop
breakon ruleNumber = Rule.quit
endloop
echonl "Bye :)"
except
echonl "Exception line ":@exceptline
if @part = 1 then
declare err
let err = 0
invoke lex&error(err)
echonl "lex error : ":err
endif
end
+48
View File
@@ -0,0 +1,48 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
typedef struct {
Dynamic key; /* keeps the keys during cipher/decipher */
} modContextCipher;
/* codes a passer a la fonction setError */
enum {
CIPHER_OK = 0,
CIPHER_KEYLENGTH = 1,
CIPHER_MEM = 2
};
WAPIDECL void cipherInit(env * e, modContextCipher * ctx);
WAPIDECL void cipherEnd(env * e, modContextCipher * ctx);
WAPIDECL long cipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long cipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long cipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES128(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES192(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
WAPIDECL long decipher_AES256(env * e, modContextCipher * ctx, var * cle, var * in, var * out);
+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;
}
+37 -10
View File
@@ -8,8 +8,10 @@ gcc -c w_src/hashtable.c -s -Wall -DUNIX -m64 -fPIC -o exec/hashtable.o
gcc -c w_src/buffer.c -s -Wall -DUNIX -m64 -fPIC -o exec/buffer.o
gcc -c w_src/global.c -s -Wall -DUNIX -m64 -fPIC -o exec/global.o
gcc -c w_src/rep.c -s -Wall -DUNIX -m64 -fPIC -o exec/rep.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o -o exec/libw.so
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o
gcc -c w_src/lex.c -s -Wall -DUNIX -m64 -fPIC -o exec/lexw.o
gcc -c w_src/convert.c -s -Wall -DUNIX -m64 -fPIC -o exec/convert.o
gcc -shared -s exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o exec/lexw.o exec/convert.o -o exec/libw.so
rm -f exec/dynamic.o exec/var.o exec/hashtable.o exec/global.o exec/rep.o exec/buffer.o exec/lexw.o exec/convert.o
echo 1. Compilation de templateMod.c
gcc -shared -s -o exec/template.o w_src/templateMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
@@ -21,13 +23,22 @@ echo 3. Compilation de sockMod.c
gcc -shared -s -o exec/sock_lib.so w_src/sock_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/sock.o w_src/sockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:sock_lib.so
#echo 4. Compilation de dbMod.c et dbpgsql.c
echo 3b. Compilation de securesockMod.c
gcc -shared -s -o exec/securesock_lib.so w_src/securesock_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -lssl -lcrypto -l:sock_lib.so
gcc -shared -s -o exec/securesock.o w_src/securesockMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:securesock_lib.so
echo 3c. Compilation de sshMod.c
gcc -shared -s -o exec/wssh_lib.so w_src/ssh_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -lssl -lcrypto -lssh
gcc -shared -s -o exec/wssh.o w_src/sshMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:wssh_lib.so
#echo 4. Compilation de sqlite
#gcc -shared -s -o exec/db.o w_src/dbMod.c -m64 -DUNIX -Wall -ldl -fPIC -L./exec -l:libw.so
#gcc -shared -s -o exec/pgsql.o w_src/dbpgsql.c -m64 -DUNIX -Wall -I/usr/include/postgresql -fPIC -L./exec -l:libw.so
#gcc -shared -s -o exec/libsqlite3.so w_src/sqlite3.c -m64 -fPIC -lpthread -ldl -lm
gcc -shared -s -o exec/sqlite_lib.so w_src/sqlite_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 4. Compilation de encodMod.c
gcc -shared -s -o exec/encod_lib.so w_src/encod_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -Wno-char-subscripts
#gcc -shared -s -o exec/encod.o w_src/encodMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:encod_lib.so
echo 4. Compilation de convdMod.c
gcc -shared -s -o exec/conv.o w_src/convMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 5. Compilation de lzwMod.c
gcc -shared -s -o exec/lzw_lib.so w_src/lzw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
@@ -49,7 +60,12 @@ echo 7. Compilation de timeMod.c
gcc -shared -s -o exec/time.o w_src/timeMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 8. Compilation de hashMod.c
gcc -shared -s -o exec/hash.o w_src/hashMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/hash_lib.so w_src/hash_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/hash.o w_src/hashMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:hash_lib.so
echo 8b. Compilation de cipherMod.c
gcc -shared -s -o exec/cipher_lib.so w_src/cipher_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/cipher.o w_src/cipherMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:cipher_lib.so
echo 9. Compilation de systemMod.c
gcc -shared -s -o exec/system.o w_src/systemMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
@@ -57,11 +73,22 @@ gcc -shared -s -o exec/system.o w_src/systemMod.c -m64 -DUNIX -Wall -fPIC -L./ex
echo 10. Compilation de randomMod.c
gcc -shared -s -o exec/random.o w_src/randomMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 10b. Compilation de lexMod.c
gcc -shared -s -o exec/lex.o w_src/lexMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
echo 10c. Compilation de fastcgi/http/raw/websocket
gcc -shared -s -o exec/raw_lib.so w_src/raw_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/fcgi_lib.so w_src/fcgi_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/http_lib.so w_src/http_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/websocket_lib.so w_src/websocket_lib.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so
gcc -shared -s -o exec/http.o w_src/httpMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:http_lib.so
gcc -shared -s -o exec/fcgi.o w_src/fcgiMod.c -m64 -DUNIX -Wall -fPIC -L./exec -l:libw.so -l:fcgi_lib.so
echo 11. Compilation et link de langage.c
gcc w_src/langage.c -s -o exec/lw -ldl -m64 -DUNIX -DBUILD=$BUILD -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:shm_lib.so
gcc w_src/langage.c -s -o exec/lw -ldl -m64 -DUNIX -DBUILD=$BUILD -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:shm_lib.so -l:lzw_lib.so
echo 12. Compilation et link de assembler.c
gcc w_src/assembler.c -s -o exec/lwa -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so
gcc w_src/assembler.c -s -o exec/lwa -ldl -m64 -DUNIX -Wall -Wno-stringop-truncation -L./exec -l:libw.so -l:lzw_lib.so
echo 13. Generation du formatteur de code
gcc w_src/format.c -s -o exec/lwf -Wall -m64 -DUNIX -L./exec -l:libw.so
@@ -72,7 +99,7 @@ gcc w_src/genlex.c -o exec/wlex -s -Wall -m64 -DUNIX -L./exec -l:libw.so
echo 15. Generation de l\'analyseur de source w \(compilateur w\)
gcc w_src/genw.c -s -o exec/lwc -Wall -m64 -DUNIX -Wno-stringop-truncation -L./exec -l:libw.so
echo "test_utf => gcc test_utf.c -s -o utf -Wall -m64 -DUNIX -L./exec -l:libw.so"
echo "test_utf => gcc test_utf.c -s -o utf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:lzw_lib.so"
echo "test_pdf => gcc test_pdf.c -s -o pdf -Wall -m64 -DUNIX -L./exec -l:libw.so -l:pdf_lib.so -l:lzw_lib.so"
echo "package => dpkg-deb --build wlanguage"
+55 -25
View File
@@ -7,67 +7,97 @@ cd "C:\Users\Poupougne42\source\repos\win_w_src"
echo ------------------------------------------------------------------------------------------
echo 0. Compilation pour dynamic lib DLL
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\libw.dll w_src\dynamic.c w_src\var.c w_src\hashtable.c w_src\buffer.c w_src\global.c w_src\rep.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\libw.dll w_src\dynamic.c w_src\var.c w_src\hashtable.c w_src\buffer.c w_src\global.c w_src\rep.c w_src\lex.c w_src\convert.c /DEBUG:NONE
echo 1a. Compilation de templateMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\template.dll w_src\templateMod.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\template.dll w_src\templateMod.c exec\libw.lib /DEBUG:NONE
echo 1b. Compilation de fileMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\file.dll w_src\fileMod.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\file.dll w_src\fileMod.c exec\libw.lib /DEBUG:NONE
echo 1c. Compilation de timeMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\time.dll w_src\timeMod.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\time.dll w_src\timeMod.c exec\libw.lib /DEBUG:NONE
echo 1d. Compilation de hashMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\hash.dll w_src\hashMod.c exec\libw.lib
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\hash_lib.dll w_src\hash_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\hash.dll w_src\hashMod.c exec\libw.lib exec\hash_lib.lib /DEBUG:NONE
echo 1e. Compilation de systemMod.c (ws2_32.lib pour socket)
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\system.dll w_src\systemMod.c exec\libw.lib ws2_32.lib advapi32.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\system.dll w_src\systemMod.c exec\libw.lib ws2_32.lib advapi32.lib /DEBUG:NONE
echo 1f. Compilation de randomMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\random.dll w_src\randomMod.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\random.dll w_src\randomMod.c exec\libw.lib /DEBUG:NONE
echo 1g. Compilation de cipherMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\cipher_lib.dll w_src\cipher_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\cipher.dll w_src\cipherMod.c exec\libw.lib exec\cipher_lib.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 2a. Compilation de jsonMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\json_lib.dll w_src\json_lib.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\json_lib.dll w_src\json_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib /DEBUG:NONE
echo 2b. Compilation de shmMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\shm_lib.dll w_src\shm_lib.c exec\libw.lib advapi32.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\shm.dll w_src\shmMod.c exec\libw.lib exec\shm_lib.lib
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\shm_lib.dll w_src\shm_lib.c exec\libw.lib advapi32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\shm.dll w_src\shmMod.c exec\libw.lib exec\shm_lib.lib /DEBUG:NONE
echo 2c. Compilation de lzwMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\lzw_lib.dll w_src\lzw_lib.c exec\libw.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\lzw.dll w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\lzw_lib.dll w_src\lzw_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lzw.dll w_src\lzwMod.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
echo 2d. Compilation de pdfMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\pdf_lib.dll w_src\pdf_lib.c exec\libw.lib exec\lzw_lib.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\pdf.dll w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\pdf_lib.dll w_src\pdf_lib.c exec\libw.lib exec\lzw_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\pdf.dll w_src\pdfMod.c exec\libw.lib exec\pdf_lib.lib /DEBUG:NONE
echo 2e. Compilation de sockMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\sock_lib.dll w_src\sock_lib.c exec\libw.lib ws2_32.lib
cl /LD /DWINLIB /DWAPIIMPORT /Feexec\sock.dll w_src\sockMod.c exec\libw.lib exec\sock_lib.lib ws2_32.lib
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sock_lib.dll w_src\sock_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\sock.dll w_src\sockMod.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE
echo 2f. Compilation de encodMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Feexec\encod_lib.dll w_src\encod_lib.c exec\libw.lib
rem cl /LD /DWINLIB /DWAPIIMPORT /Feexec\json.dll w_src\jsonMod.c exec\libw.lib exec\json_lib.lib
echo 2eb. Compilation de securesockMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\securesock_lib.dll w_src\securesock_lib.c exec\libw.lib exec\sock_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" libssl.lib libcrypto.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\securesock.dll w_src\securesockMod.c exec\libw.lib exec\sock_lib.lib exec\securesock_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include"
echo 2ec. Compilation de sshMod.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\wssh_lib.dll w_src\ssh_lib.c exec\libw.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" ssh.lib libssl.lib libcrypto.lib z.lib
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\wssh.dll w_src\sshMod.c exec\libw.lib exec\wssh_lib.lib ws2_32.lib /DEBUG:NONE /I"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows/include" /link /LIBPATH:"C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows\lib" ssh.lib libssl.lib libcrypto.lib z.lib
echo 2f. Compilation de convMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\conv.dll w_src\convMod.c exec\libw.lib /DEBUG:NONE
echo 2g. Compilation de lexMod.c
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lex.dll w_src\lexMod.c exec\libw.lib /DEBUG:NONE
echo 2h. Compilation de fcgi.c/http.c
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\raw_lib.dll w_src\raw_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\fcgi_lib.dll w_src\fcgi_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\http_lib.dll w_src\http_lib.c exec\libw.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\websocket_lib.dll w_src\websocket_lib.c exec\libw.lib exec\hash_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\http.dll w_src\httpMod.c exec\libw.lib exec\http_lib.lib /DEBUG:NONE
cl /LD /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\fcgi.dll w_src\fcgiMod.c exec\libw.lib exec\fcgi_lib.lib /DEBUG:NONE
echo 2i. Compilation de sqlite
cl /LD /Gy /MD /Feexec\sqlite3.dll w_src\sqlite3.c /DSQLITE_API=__declspec(dllexport) /DEBUG:NONE
cl /LD /DWINLIB /DWAPIEXPORT /Gy /MD /Feexec\sqlite_lib.dll w_src\sqlite_lib.c exec\libw.lib exec\sqlite3.lib /DEBUG:NONE
echo ------------------------------------------------------------------------------------------
echo 3a. Generation lw.exe
cl w_src\langage.c /DWINLIB /DWAPIIMPORT /Feexec\lw.exe exec\libw.lib exec\shm_lib.lib advapi32.lib /link
cl w_src\langage.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lw.exe exec\libw.lib exec\shm_lib.lib exec\lzw_lib.lib advapi32.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3b. Generation lwa.exe
cl w_src\assembler.c /DWINLIB /DWAPIIMPORT /Feexec\lwa.exe exec\libw.lib /link
cl w_src\assembler.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwa.exe exec\libw.lib exec\lzw_lib.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3c. Generation lwc.exe
cl w_src\genw.c /DWINLIB /DWAPIIMPORT /Feexec\lwc.exe exec\libw.lib /link
cl w_src\genw.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwc.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3d. Generation lwf.exe
cl w_src\format.c /DWINLIB /DWAPIIMPORT /Feexec\lwf.exe exec\libw.lib /link
cl w_src\format.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\lwf.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo 3d. Generation wlex.exe
cl w_src\genlex.c /DWINLIB /DWAPIIMPORT /Feexec\wlex.exe exec\libw.lib /link
cl w_src\genlex.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\wlex.exe exec\libw.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
rem echo 3e. Generation test.exe
rem cl w_src\test.c /DWINLIB /DWAPIIMPORT /Gy /MD /Feexec\test.exe exec\libw.lib exec\encod_lib.lib /link /DEBUG:NONE /OPT:REF /OPT:ICF
echo ------------------------------------------------------------------------------------------
echo 4. Purge
+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;
}
+71 -28
View File
@@ -20,7 +20,13 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "encod.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "langage.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
@@ -53,7 +59,6 @@ static char hexa[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };
static char carhex[16] = {"0123456789abcdef"};
// TODO static char carHEX[16] = {"0123456789ABCDEF"};
static char base64[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
@@ -92,8 +97,8 @@ WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat)
/* cette methode fonctionne aussi si this et resultat pointent sur la meme variable... mettre TRUE dans dynCtrl alors ! */
for( ;from >= 0; )
{
resultat->mPtr[to--] = carhex[this->mPtr[from] % 16];
resultat->mPtr[to--] = carhex[this->mPtr[from--] / 16];
resultat->ptr[to--] = carhex[this->ptr[from] % 16];
resultat->ptr[to--] = carhex[this->ptr[from--] / 16];
}
dynSetLen(e, resultat, this->mLg * 2);
return DYN_OK;
@@ -127,26 +132,26 @@ WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat)
if(from + 1 >= this->mLg)
{
/* bloc de 1 octet => 2 cars en sortie + 2 cars de complement */
resultat->mPtr[to++] = carBase64[this->mPtr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->mPtr[from] & 3) << 4)];
resultat->mPtr[to++] = carBase64[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4)];
resultat->mPtr[to++] = carBase64[64];
resultat->mPtr[to++] = carBase64[64];
/* */
} else if(from + 2 >= this->mLg)
{
/* bloc de 2 octets => 3 cars en sortie + 1 car en complement */
resultat->mPtr[to++] = carBase64[this->mPtr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->mPtr[from] & 3) << 4) | (this->mPtr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->mPtr[from + 1] & 15) << 2)];
resultat->mPtr[to++] = carBase64[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4) | (this->ptr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->ptr[from + 1] & 15) << 2)];
resultat->mPtr[to++] = carBase64[64];
}
else
{
/* bloc de 3 octets => 4 cars en sortie */
resultat->mPtr[to++] = carBase64[this->mPtr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->mPtr[from] & 3) << 4) | (this->mPtr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->mPtr[from + 1] & 15) << 2) | (this->mPtr[from + 2] >> 6)];
resultat->mPtr[to++] = carBase64[this->mPtr[from + 2] & 63];
resultat->mPtr[to++] = carBase64[this->ptr[from] >> 2];
resultat->mPtr[to++] = carBase64[((this->ptr[from] & 3) << 4) | (this->ptr[from + 1] >> 4)];
resultat->mPtr[to++] = carBase64[((this->ptr[from + 1] & 15) << 2) | (this->ptr[from + 2] >> 6)];
resultat->mPtr[to++] = carBase64[this->ptr[from + 2] & 63];
}
}
/* */
@@ -170,9 +175,12 @@ WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat)
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 2)
{
if((c1 = hexa[this->mPtr[from]]) == -1 || (c2 = hexa[this->mPtr[from + 1]]) == -1)
if((c1 = hexa[this->ptr[from]]) == -1 || (c2 = hexa[this->ptr[from + 1]]) == -1)
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* erreur format hexa incorrect */
resultat->mPtr[to++] = (c1 << 4) | c2;
}
resultat->ptr[to++] = (c1 << 4) | c2;
}
dynSetLen(e, resultat, this->mLg / 2);
return DYN_OK;
@@ -199,28 +207,34 @@ WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat)
long from, to;
for(from = 0, to = 0; from < this->mLg; from += 4, to += 3)
{
char c1 = base64[this->mPtr[from]];
char c2 = base64[this->mPtr[from + 1]];
char c3 = base64[this->mPtr[from + 2]];
char c4 = base64[this->mPtr[from + 3]];
char c1 = base64[this->ptr[from]];
char c2 = base64[this->ptr[from + 1]];
char c3 = base64[this->ptr[from + 2]];
char c4 = base64[this->ptr[from + 3]];
if(c1 == -1 || c2 == -1 || c3 == -1 || c4 == -1 || c1 == 99 || c2 == 99 || (c3 == 99 && c4 != 99))
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* erreur format base64 incorrect */
}
if(c4 == 99 && from + 4 < this->mLg)
{
dynSetLen(e, resultat, 0);
return DYN_ERR; /* '=' autorise en fin de chaine uniquement */
}
//
resultat->mPtr[to] = 0;
resultat->mPtr[to + 1] = 0;
resultat->mPtr[to + 2] = 0;
resultat->mPtr[to] = c1 << 2;
resultat->mPtr[to] |= c2 >> 4;
resultat->ptr[to] = 0;
resultat->ptr[to + 1] = 0;
resultat->ptr[to + 2] = 0;
resultat->ptr[to] = c1 << 2;
resultat->ptr[to] |= c2 >> 4;
if(c3 != 99)
{
resultat->mPtr[to + 1] = (c2 & 15) << 4;
resultat->mPtr[to + 1] |= c3 >> 2;
resultat->ptr[to + 1] = (c2 & 15) << 4;
resultat->ptr[to + 1] |= c3 >> 2;
if(c4 != 99)
{
resultat->mPtr[to + 2] = (c3 & 3) << 6;
resultat->mPtr[to + 2] |= c4;
resultat->ptr[to + 2] = (c3 & 3) << 6;
resultat->ptr[to + 2] |= c4;
}
else
lgClair--;
@@ -231,3 +245,32 @@ WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat)
dynSetLen(e, resultat, lgClair);
return DYN_OK;
}
WAPIDECL void str2upper(env * e, Dynamic * this)
{
long i;
for(i = 0; i < this->mLg; i++)
if(this->mPtr[i] >= 'a' && this->mPtr[i] <= 'z')
this->mPtr[i] -= 32;
}
WAPIDECL void str2lower(env * e, Dynamic * this)
{
long i;
for(i = 0; i < this->mLg; i++)
if(this->mPtr[i] >= 'A' && this->mPtr[i] <= 'Z')
this->mPtr[i] += 32;
}
WAPIDECL ent64s hex2num(env * e, Dynamic * this)
{
ent64s resultat = 0;
char c;
long i;
for(i = 0; i < this->mLg; i++)
if((c = hexa[this->ptr[i]]) == -1)
break; // erreur hexa : fin de la conversion
else
resultat = (resultat << 4) + (ent64s)c;
return resultat;
}
+7 -7
View File
@@ -20,17 +20,17 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#ifndef CONVERT_H
#define CONVERT_H
#include "langage.h"
#include "dynamic.h"
typedef struct {
int dum;
} modContextEncod;
WAPIDECL long str2hex(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long str2base64(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long hex2str(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL long base642str(env * e, Dynamic * this, Dynamic * resultat);
WAPIDECL void str2upper(env * e, Dynamic * this);
WAPIDECL void str2lower(env * e, Dynamic * this);
WAPIDECL ent64s hex2num(env * e, Dynamic * this);
#endif
+31 -17
View File
@@ -77,12 +77,20 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(param == NULL || etat == NULL)
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de le faire a chaque fonction */
if(param->type == VAR_PARAM)
param = (var *)param->ptr; /* evite de le faire a chaque fonction */
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
@@ -97,39 +105,45 @@ extern long execModule(env * e, var * param, var * param2, var * param3, void **
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
memset(p_etat->base, 0, LGNOMBASE + 1);
p_etat->ctx = NULL;
p_etat->fnDb = NULL;
//
}
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
//*** code specifique ici
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param->type == VAR_DYNAMIC)
dynLet(e, param, "1", 1); //*** version en alpha
else if(param->type == VAR_NUMBER)
param->num = NUM_UN; //*** version en numerique
if(param1 == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param->type == VAR_NUMBER)
param->num = (ent64)(NUM_FACTEUR * p_etat->error);
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
exc = EX_MODPARAM; // bad type of parameter
}
}
/* ============================================================================================= */
+26 -10
View File
@@ -60,7 +60,12 @@ char * strerr[] = {
"EX_REMOVE_KO remove field error",
"EX_CHILD_FORK cannot fork process",
"EX_CHILD_EXEC cannot run new process",
"EX_ZERO_FOR_INCR foreach increment is zero" // 40
"EX_ZERO_FOR_INCR foreach increment is zero", // 40
"EX_SORTEDSEARCH_KO sort type incorrect",
"EX_SQRT_NEG square root of a negative number is not calculated.",
"EX_INT_EXP Fractional exponentiation is not calculated",
"EX_VARPARAM_KO Null parameter pointer",
"EX_PARAM_NOTFOUND Named parameter not found"
};
enum {
@@ -103,7 +108,17 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
void print_var(env * e, var * v, Dynamic * tmp, int prettyPrint)
{
if(v->type == VAR_PARAM)
{
v = (var *)v->ptr; /* travailler avec la var pointee */
if(v == NULL)
{
if(e->demon)
dynPrintfSz(e, "Null parameter pointer\n", NULL);
else
printf("Null parameter pointer\n");
return;
}
}
//
char * var_str[9] = {"0","X","N","S","P","D","H","O","B"};
if(e->demon)
@@ -164,7 +179,7 @@ void print_var(env * e, var * v, Dynamic * tmp, int prettyPrint)
dynPrintfHex(e, PRINTF_MARK ")\n", (ent64)v->ptr, 0); // S
break;
case VAR_PARAM:
dynPrintfSz(e, "Var " PRINTF_MARK "\n", var_str[v->type]); // P : mais ne peut pas arriver ici
dynPrintfSz(e, "Var " PRINTF_MARK "\n", var_str[v->type]); // P : mais ne peut pas arriver ici normalement (VAR_PARAM de VAR_PARAM non gere)
break;
}
else
@@ -216,7 +231,7 @@ void print_var(env * e, var * v, Dynamic * tmp, int prettyPrint)
printf("Var %c : %p (-> %p)\n",e->var_car[v->type], v, v->ptr); // S
break;
case VAR_PARAM:
printf("Var %c\n",e->var_car[v->type]); // P : mais ne peut pas arriver ici
printf("Var %c\n",e->var_car[v->type]); // P : mais ne peut pas arriver ici normalement (VAR_PARAM de VAR_PARAM non gere)
break;
}
}
@@ -369,6 +384,7 @@ void debug(env * e)
dynPrintfInt64(e, "W" PRINTF_MARK, VERSION, 0);
if( ! srcFound)
dynPrintfInt64(e, ":" PRINTF_MARK, e->ligsrc, 0);
dynPrintfInt64(e, "!" PRINTF_MARK, e->except_ex, 0);
dynPrintfSz(e, "> ", NULL);
writeShm(e, (modContextShm *)e->debugCtxShm);
//
@@ -392,9 +408,9 @@ void debug(env * e)
{
// prompt
if(srcFound)
printf("W%d> ", VERSION);
printf("W%d!%lld> ", VERSION, e->except_ex);
else
printf("W%d:%lld> ", VERSION, e->ligsrc);
printf("W%d:%lld!%lld> ", VERSION, e->ligsrc, e->except_ex);
dynSetLen(e, &e->debugcmd, 0);
int c;
char cmd[2];
@@ -471,7 +487,7 @@ void debug(env * e)
}
/* trt cmd ; e->debugcmd sert de variable tmp ici */
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X");
hex2str(e, &tmp, &e->debugcmd);
if(dynCompare(e, &e->debugcmd, CMP_EQ, "vg", 2) || dynCompare(e, &e->debugcmd, CMP_EQ, "VG", 2))
{
/* voir le contenu d'une variable */
@@ -498,7 +514,7 @@ void debug(env * e)
break;
}
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X");
hex2str(e, &tmp, &e->debugcmd);
if(e->debugcmd.mLg < 2 || e->debugcmd.mLg > 24)
{
if(e->demon)
@@ -673,7 +689,7 @@ void debug(env * e)
else
{
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X"); // e->debugcmd = numLigne
hex2str(e, &tmp, &e->debugcmd); // e->debugcmd = numLigne
long numLigne = dynToNum(e, &e->debugcmd, FALSE, 9);
long pos = dynSortLocateSz(e, &e->debugbrkpoint, Int64ToSz(e, numLigne, FALSE, 9), cFM, DYN_SORT_ASC, DYN_NONE, DYN_NONE);
if(pos < 0 && tok == r.ajouter)
@@ -736,7 +752,7 @@ void debug(env * e)
break;
}
dynField(e, &e->debugvalex, &tmp, 1, n, cFM, cVM, 1);
dynIconv(e, &tmp, &e->debugcmd, "X");
hex2str(e, &tmp, &e->debugcmd);
if(e->debugcmd.mLg < 2 || e->debugcmd.mLg > 24)
{
if(e->demon)
@@ -761,7 +777,7 @@ void debug(env * e)
{
hashtable_do(e, HASH_READ, e->local, e->nom, &vnext);
}
if(v == NULL)
if(vnext == NULL)
{
/* si pas trouve (ou pas de locale), cherche dans la hash "globale" */
hashtable_do(e, HASH_READ, &e->g, e->nom, &vnext);
+240 -411
View File
@@ -1310,6 +1310,8 @@ WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp
}
/* chercher le sousChamp */
nSep = 1;
if(numSousChamp == 0 && (this->mPtr[iPos + 1] == separateurChamp || iPos + 1 == this->mLg))
nSep = 0; // si champ vide et sous-champ no 1, ne pas ajouter de marque de sous-champ a la fin
for(iScan = iPos + 1; numSousChamp > 0 && iScan < this->mLg; iScan++)
if(this->mPtr[iScan] == separateurSousChamp)
{
@@ -1318,9 +1320,9 @@ WAPIDECL long dynInsSz(env * e, Dynamic * this, long numChamp, long numSousChamp
}
else if(this->mPtr[iScan] == separateurChamp)
{
iPos = iScan - 1;
nSep = 0;
break;
iPos = iScan - 1;
nSep = 0;
break;
}
else if(iScan == this->mLg - 1)
{
@@ -2424,414 +2426,6 @@ WAPIDECL long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * rempl
return DYN_OK;
}
WAPIDECL char * dynConvertCharToCharHexa(octet c)
{
static char car[16] = {"0123456789ABCDEF"};
static char res[3] = {0};
res[0] = car[c / 16];
res[1] = car[c % 16];
return res;
}
// dynOconv ne sert pas, à gérer ailleurs autrement : faire un module Convert : Hexa, base64 ; horodate a deja son module
WAPIDECL long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format)
{
/* a revoir pour UTF8 ? (Base64 ?) oui pour D car d'autres cars utf8 peuvent etre dans la chaine */
static char car[64] = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_."}; /* sert a la conv hexa et base64 */
char tmp[5], * chaine;
long lg, i;
//
chaine = this->mPtr;
lg = this->mLg;
switch(*format++)
{
case 'D': // obsolete ? utiliser le mod Horodate
{
struct tm * ptm;
/* conversion date/heure : format interne = time_t unix sur 32 bits */
time_t tm;
if(this->mLg == 0)
{
tm = time(NULL);
ptm = gmtime(&tm);
}
else
{
tm = dynToNum(e, this, DYN_NONE, 10); /* pas de signe, lg max sur 32 bits = 10 chiffres */
if(this->mInternal == DYN_ERR)
return DYN_ERR; /* pbm de conversion numerique */
ptm = localtime(&tm);
}
/* analyse formatage demande */
dynLet(e, resultat, NULL, DYN_LGNONE);
tmp[1] = 0;
while((tmp[0] = *format++))
switch(tmp[0])
{
case 'Y':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_year + 1900, DYN_NONE, 4), 4);
break;
case 'y':
dynConcatSz(e, resultat, Int32ToSz((ptm->tm_year + 1900) % 100, DYN_NONE, 2), 2);
break;
case 'M':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mon + 1, DYN_NONE, 2), 2);
break;
case 'D':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mday, DYN_NONE, 2), 2);
break;
case 'h':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_hour, DYN_NONE, 2), 2);
break;
case 'm':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_min, DYN_NONE, 2), 2);
break;
case 's':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_sec, DYN_NONE, 2), 2);
break;
default:
dynConcatSz(e, resultat, tmp, 1);
break;
}
break;
}
/* */
case 'H':
/* uniquement heure (0-86399) */
break;
/* */
case 'X':
/* conversion en hexa de toute la chaine */
tmp[2] = 0;
if(dynCtrl(e, resultat, lg * 2, DYN_FALSE)) /* chaine hexa : taille double de celle origine */
return DYN_ERR;
for(i = 0; i < lg; i++)
{
tmp[0] = car[chaine[i] / 16];
tmp[1] = car[chaine[i] % 16];
dynConcatSz(e, resultat, tmp, 2);
}
break;
/* */
case 'B':
/* conversion en base64 avec "_." comme 2 derniers cars et sans "=" a la fin (pas le "vrai" base64) */
/* 3 cars en clair en donne 4 en base 64 ; si le dernier bloc contient 2 cars, la sortie est de 3 cars */
/* si le dernier bloc contient 1 car, la sortie est de 2 cars (padding avec des bits a 0) */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
tmp[4] = 0;
if(dynCtrl(e, resultat, lg + lg / 3 + 4, DYN_FALSE)) /* chaine base64 : taille + 1/3 de la taile originale (+4 est une sécurité) */
return DYN_ERR;
for(i = 0; i < lg; i += 3)
{
if(i+1 >= lg)
{
/* bloc de 1 octet => 2 cars en sortie */
tmp[0] = car[chaine[i] >> 2];
tmp[1] = car[((chaine[i] & 3) << 4)];
tmp[2] = 0;
/* */
} else if(i+2 >= lg)
{
/* bloc de 2 octets => 3 cars en sortie */
tmp[0] = car[chaine[i] >> 2];
tmp[1] = car[((chaine[i] & 3) << 4) | (chaine[i+1] >> 4)];
tmp[2] = car[((chaine[i+1] & 15) << 2)];
tmp[3] = 0;
}
else
{
/* bloc de 3 octets => 4 cars en sortie */
tmp[0] = car[chaine[i] >> 2];
tmp[1] = car[((chaine[i] & 3) << 4) | (chaine[i+1] >> 4)];
tmp[2] = car[((chaine[i+1] & 15) << 2) | (chaine[i+2] >> 6)];
tmp[3] = car[chaine[i+2] & 63];
}
dynConcatSz(e, resultat, tmp, 4);
}
break;
}
return DYN_OK;
}
// seul dynIconv "X" sert dans w : ç gérer ailleurs et autrement
WAPIDECL long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format)
{
/* a revoir pour UTF8 ? (Base64 ?) */
static char car[64] = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_."}; /* sert a la conv hexa et base64 */
char tmp[5], * chaine, c1, c2, c3, c4;
long lg, i, conv_ok, h, b, valeur;
/* */
chaine = this->mPtr;
lg = this->mLg;
switch(*format++)
{
case 'D':
{
struct tm stm;
stm.tm_year = - 1900;
stm.tm_mon = - 1;
stm.tm_mday = 0;
stm.tm_hour = 0;
stm.tm_min = 0;
stm.tm_sec = 0;
stm.tm_isdst = -1;
/* conversion date/heure : format interne = time_t unix sur 32 bits */
while((c1 = *format++))
switch(c1)
{
case 'Y':
if(lg < 4)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 1000;
valeur += ((*chaine++) - 48) * 100;
valeur += ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 4;
stm.tm_year += valeur;
break;
case 'y':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
if(valeur > 35)
valeur += 1900;
else
valeur += 2000;
lg -= 2;
stm.tm_year += valeur;
break;
case 'M':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_mon += valeur;
break;
case 'D':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_mday += valeur;
break;
case 'h':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_hour += valeur;
break;
case 'm':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_min += valeur;
break;
case 's':
if(lg < 2)
return DYN_ERR;
valeur = ((*chaine++) - 48) * 10;
valeur += (*chaine++) - 48;
lg -= 2;
stm.tm_sec += valeur;
break;
default:
chaine++;
break;
}
if((valeur = mktime(&stm)) == -1)
return DYN_ERR;
/* */
dynLet(e, resultat, NULL, DYN_LGNONE);
dynConcatSz(e, resultat, Int32ToSz(valeur, DYN_NONE, DYN_NONE), DYN_LGNONE); /* non signe, pas de padding ; longueur pas connue */
break;
/* */
}
case 'H':
/* uniquement heure (0-86399) */
break;
/* */
case 'X':
/* conversion en clair de la chaine en hexa */
tmp[1] = 0;
if(dynCtrl(e, resultat, lg / 2 + 1, DYN_FALSE))
return DYN_ERR;
for(i = 0; i < lg; i += 2)
{
conv_ok = DYN_FALSE;
c1 = chaine[i];
c2 = chaine[i + 1]; /* si impair, c2 est le \0 de fin de chaine... */
for(h = 0; h < 16 && !conv_ok; h++)
if(c1 == car[h])
{
tmp[0] = h << 4; /* fois 16 */
for(h = 0; h < 16; h++)
if(c2 == car[h])
{
tmp[0] |= h;
dynConcatSz(e, resultat, tmp, 1);
conv_ok = DYN_TRUE;
break;
}
}
if(!conv_ok)
return DYN_ERR;
}
break;
/* */
case 'B':
/* conversion en clair de la chaine en base64 avec "_." comme 2 derniers cars et sans "=" a la fin (pas le "vrai" base64) */
/* multiple de 4 => bloc de 4 donne 3 cars en clair ; bloc de 3 donne 2 en clair ; bloc de 2 donne 1 en clair */
/* bloc de 1 est une erreur : ne sera pas traite */
/* +-------------+-----------+-------------+ */
/* | 6 | 2 | 4 | 4 | 2 | 6 | */
/* +---------+---------+---------+---------+ */
tmp[3] = 0;
if(dynCtrl(e, resultat, lg - lg / 4 + 4, DYN_FALSE))
return DYN_ERR;
for(i = 0; i < lg; i += 4)
{
conv_ok = DYN_FALSE;
c1 = chaine[i];
if(i + 1 >= lg)
{
/* bloc de 1 octet => erreur et arret du decodage */
/* */
} else if(i + 2 >= lg)
{
/* bloc de 2 octets => 1 car en clair */
c2 = chaine[i + 1];
for(b = 0; b < 64 && !conv_ok; b++)
if(c1 == car[b])
{
tmp[0] = b << 2;
for(b = 0; b < 64; b++)
if(c2 == car[b])
{
tmp[0] |= b >> 4;
tmp[1] = 0;
dynConcatSz(e, resultat, tmp, 1);
conv_ok = DYN_TRUE;
break;
}
}
/* */
} else if(i + 3 >= lg)
{
/* bloc de 3 octets => 2 cars en clair */
c2 = chaine[i + 1];
c3 = chaine[i + 2];
for(b = 0; b < 64 && !conv_ok; b++)
if(c1 == car[b])
{
tmp[0] = b << 2;
for(b = 0; b < 64 && !conv_ok; b++)
if(c2 == car[b])
{
tmp[0] |= b >> 4;
tmp[1] = (b & 15) << 4;
for(b = 0; b < 64; b++)
if(c3 == car[b])
{
tmp[1] |= b >> 2;
tmp[2] = 0;
dynConcatSz(e, resultat, tmp, 2);
conv_ok = DYN_TRUE;
break;
}
}
}
}
else
{
/* bloc de 4 octets => 3 cars en clair */
c2 = chaine[i + 1];
c3 = chaine[i + 2];
c4 = chaine[i + 3];
for(b = 0; b < 64 && !conv_ok; b++)
if(c1 == car[b])
{
tmp[0] = b << 2;
for(b = 0; b < 64 && !conv_ok; b++)
if(c2 == car[b])
{
tmp[0] |= b >> 4;
tmp[1] = (b & 15) << 4;
for(b = 0; b < 64 && !conv_ok; b++)
if(c3 == car[b])
{
tmp[1] |= b >> 2;
tmp[2] = (b & 3) << 6;
for(b = 0; b < 64; b++)
if(c4 == car[b])
{
tmp[2] |= b;
dynConcatSz(e, resultat, tmp, 3);
conv_ok = DYN_TRUE;
break;
}
}
}
}
}
if(!conv_ok)
return DYN_ERR;
}
break;
}
return DYN_OK;
}
// mettre ailleurs ? module convert ?
WAPIDECL long dynConvertHexaToLong(Dynamic * valeur)
{
static long hexa[128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
//
long resultat = 0;
for(long cptCar = 0; cptCar < valeur->mLg; cptCar++)
resultat = (resultat * 16) + hexa[valeur->mPtr[cptCar] & 127];
return resultat;
}
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c)
{
static char hexa[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128 cars a la fin de cette ligne */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
if((hexa[(unsigned char)c1] == 0 && c1 != '0') || (hexa[(unsigned char)c2] == 0 && c2 != '0'))
return DYN_ERR; // erreur format hexa incorrect
*c = hexa[(unsigned char)c1] * 16 + hexa[(unsigned char)c2];
return DYN_OK;
}
WAPIDECL long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg)
{
/* a revoir pour UTF8, cf. dynFmtUtf8 */
@@ -3058,6 +2652,54 @@ WAPIDECL long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadr
return DYN_OK;
}
WAPIDECL void dynTrimSpace(env * e, Dynamic * this)
{
char * lire;
char * ecrire;
int etat = 0; /* 0 = debut chaine, 1 = milieu et fin, 2 = milieu et fin avec un espace ecrit */
/* trim de la chaine : enleve les <car> en debut et fin de chaine, au "milieu" en laisse un seul */
lire = this->mPtr;
ecrire = this->mPtr;
/* */
while(*lire != 0)
switch(etat)
{
case 0:
/* debut de chaine */
if(*lire == 32)
lire++;
else
{
*ecrire++ = *lire++;
etat = 1;
}
break;
case 1:
/* milieu/fin de chaine */
if(*lire == 32)
{
etat = 2;
}
*ecrire++ = *lire++;
break;
case 2:
/* milieu/fin de chaine avec un espace ecrit */
if(*lire == 32)
lire++;
else
{
*ecrire++ = *lire++;
etat = 1;
}
break;
}
if(etat == 2)
{
ecrire--;
}
dynSetLen(e, this, ecrire - this->mPtr);
}
WAPIDECL long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option)
{
/* a revoir pour UTF8, cf. dynTrimUtf8 */
@@ -3170,4 +2812,191 @@ WAPIDECL long dynTrimUtf8(env * e, Dynamic * this, Dynamic * resultat, char * ca
return DYN_OK;
}
WAPIDECL void dynCut(env * e, Dynamic * this, long pos)
{
/* le car situe a <position> est le premier garde */
if (pos <= 0 || this->mLg < 1)
return;
if(pos >= this->mLg)
{
// position de cut superieure a la longueur de la chaine : on vide la chaine
this->mLg = 0;
this->mPtr[this->mLg] = 0;
return;
}
long lg = this->mLg - pos;
memcopie(this->mPtr, this->mPtr + pos, lg);
this->mLg = lg;
this->mPtr[this->mLg] = 0;
}
WAPIDECL long dynCleanString(env * e, Dynamic * this, octet debutGarde, octet finGarde, long convHexa)
{
/* nettoie la chaine <this> des octets dont le code ascii n'est PAS dans [debutGarde, finGarde]
convHexa : FALSE pour supprimer et ne pas convertir en hexa #xx, TRUE garder le car et mis en hexa #xx
*/
if(this == NULL || debutGarde > finGarde)
return DYN_ERR;
if(this->mLg == 0)
return DYN_OK;
/* */
if(convHexa)
{
long scan = 0, lgc = 1, lgr = 3;
do
{
if(this->mPtr[scan] >= debutGarde && this->mPtr[scan] <= finGarde)
scan++;
else
{
// repris de dynChange, quand remplace est plus grand que cherchee : insertion de 2 cars
// car remplace par # et insertion du code ascii (remplace 1 octet (lgc) par 3 octets (lgr))
// scan = pos_p ( => p - this->mPtr )
if(dynCtrl(e, this, this->mLg + lgr - lgc, DYN_TRUE))
return DYN_ERR; // erreur memoire
char * p = this->mPtr + scan;
//
// deplacement depuis la fin
long n = this->mLg - scan - lgc + 1; // +1 pour copier le \0 de fin...
memcopie(p + lgr, p + lgc, n);
//
char * hex = dynConvertCharToCharHexa((octet)(*p));
*p++ = '#';
*p++ = hex[0];
*p++ = hex[1];
//
this->mLg += (lgr - lgc);
scan += lgr;
}
} while (scan < this->mLg);
/* this->mLg et 0 de fin deja a jour */
this->mPtr[this->mLg] = 0;
}
else
{
/* equivalent a dynErase sur octets hors de la plage de codes ASCII, PAS de gestion UTF8 ici, uniquement octets */
long i, pos = 0;
for(i = 0; i < this->mLg; i++)
{
if(this->mPtr[i] >= debutGarde && this->mPtr[i] <= finGarde)
{
if(pos != i) /* pour ne pas recopier les premiers caracteres quand pas de suppression */
this->mPtr[pos++] = this->mPtr[i];
else
pos++;
}
}
this->mLg = pos;
this->mPtr[this->mLg] = 0;
}
return DYN_OK;
}
WAPIDECL char * dynConvertCharToCharHexa(octet c)
{
static char car[16] = {"0123456789ABCDEF"};
static char res[3] = {0};
res[0] = car[c / 16];
res[1] = car[c % 16];
return res;
}
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c)
{
static char hexa[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128 cars a la fin de cette ligne */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
if((hexa[(unsigned char)c1] == 0 && c1 != '0') || (hexa[(unsigned char)c2] == 0 && c2 != '0'))
return DYN_ERR; // erreur format hexa incorrect
*c = hexa[(unsigned char)c1] * 16 + hexa[(unsigned char)c2];
return DYN_OK;
}
WAPIDECL void dynCleanHexaMark(env * e, Dynamic * this)
{
if(this == NULL)
return;
/* */
/* equivalent a dynErase sur #xx, suppression "xx" et remplacement # par l'octet "xx" */
long i, pos = 0;
for(i = 0; i < this->mLg; i++)
{
if(this->mPtr[i] != '#' || i >= this->mLg - 2) // car si pas la place pour le code ascii, ne pas traiter # comme debut du code (securite)
{
if(pos != i) /* pour ne pas recopier les premiers caracteres quand pas de suppression */
this->mPtr[pos++] = this->mPtr[i];
else
pos++;
}
else
{
// remplace #xx (hexa) par l'octet correspondant
if(dynConvertCharHexaToChar(this->mPtr[i + 1], this->mPtr[i + 2], &this->mPtr[pos]) == DYN_ERR)
this->mPtr[pos] = '?'; // securite
pos++;
i += 2;
}
}
this->mLg = pos;
this->mPtr[this->mLg] = 0;
}
WAPIDECL long dynEscapeHexaMark(env * e, Dynamic * this)
{
/* remplace les sequences #xx par leur version echapee #23 #12 #34 */
/* ok en utf8 */
char c1, c2, c, * res;
long i;
for(i = 0; i < this->mLg; )
{
if(this->mPtr[i] == '#' && i < this->mLg - 2)
{
c1 = this->mPtr[i + 1];
c2 = this->mPtr[i + 2];
if(dynConvertCharHexaToChar(c1, c2, &c) == DYN_OK)
{
if(dynCtrl(e, this, this->mLg + 6, TRUE))
return DYN_ERR;
this->mPtr[i + 1] = '2';
this->mPtr[i + 2] = '3'; /* \x23 = # */
/* inserer 6 cars a (i + 3) */
/* deplacer la fin s'il y en a une */
if(this->mLg > i + 3)
memcopie(this->mPtr + i + 3 + 6, this->mPtr + i + 3, this->mLg - i - 3); // si lg a deplacer = 0, memcopie ne fait rien
this->mLg += 6;
this->mPtr[this->mLg] = 0;
/* */
res = dynConvertCharToCharHexa(c1);
this->mPtr[i + 3] = '#';
this->mPtr[i + 4] = res[0];
this->mPtr[i + 5] = res[1];
res = dynConvertCharToCharHexa(c2);
this->mPtr[i + 6] = '#';
this->mPtr[i + 7] = res[0];
this->mPtr[i + 8] = res[1];
/* */
i += 9;
}
else
return DYN_ERR;
}
else
i++;
}
return DYN_OK;
}
/* ********************************************** */
+12 -9
View File
@@ -23,10 +23,10 @@
#ifndef DYNAMIC_H
#define DYNAMIC_H
#define cFM '\xFE' /* 254 */
#define cFM '\xFE' /* 254 */
#define cVM '\xFD' /* 253 */
#define cSVM '\xFC' /* 252 */
#define cTM '\xFB' /* 251 */
#define cSVM '\xFC' /* 252 */
#define cTM '\xFB' /* 251 */
#define sFM "\xFE"
#define sVM "\xFD"
#define sSVM "\xFC"
@@ -47,7 +47,8 @@ enum {
DYN_SORT_ASC = 1,
DYN_SORT_DESC = 2,
DYN_NOTFOUND = -1 // quand pas trouve (index...)
DYN_NOTFOUND = -1, // quand index ne trouve pas
DYN_NOTLOCATED = 0 // locate ne trouve pas
};
/*typedef struct
@@ -139,16 +140,18 @@ WAPIDECL long dynIndex(env * e, Dynamic * this, Dynamic * valeur, long occ);
WAPIDECL long dynIndexSzUtf8(env * e, Dynamic * this, char * chaine, long lgChaine, long occ);
WAPIDECL long dynChange(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long dynChangeUtf8(env * e, Dynamic * this, char * chaine, char * remplace, long nb);
WAPIDECL long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
WAPIDECL long dynIconv(env * e, Dynamic * this, Dynamic * resultat, char * format);
WAPIDECL char * dynConvertCharToCharHexa(octet c);
WAPIDECL long dynConvertHexaToLong(Dynamic * valeur);
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c);
WAPIDECL long dynFmt(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char filler, long lg);
WAPIDECL long dynFmtUtf8(env * e, Dynamic * this, Dynamic * resultat, char cadrage, char * filler, long lg);
WAPIDECL long dynFmtNumber(env * e, ent64s valeur, Dynamic * resultat, char cadrage, char filler, long lg);
WAPIDECL void dynTrimSpace(env * e, Dynamic * this);
WAPIDECL long dynTrim(env * e, Dynamic * this, Dynamic * resultat, char car, long option);
WAPIDECL long dynTrimUtf8(env * e, Dynamic * this, Dynamic * resultat, char * car, long option);
WAPIDECL void dynCut(env * e, Dynamic * this, long pos);
WAPIDECL long dynCleanString(env * e, Dynamic * this, octet debut, octet fin, long convHexa);
WAPIDECL char * dynConvertCharToCharHexa(octet c);
WAPIDECL long dynConvertCharHexaToChar(char c1, char c2, char * c);
WAPIDECL void dynCleanHexaMark(env * e, Dynamic * this);
WAPIDECL long dynEscapeHexaMark(env * e, Dynamic * this);
/* ********************************************** */
#endif
+140
View File
@@ -0,0 +1,140 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
// --- gestion protocole fastcgi
typedef struct {
long keepAlive;
long resteALireEntete;
long resteALireCorps;
char typeMessage; // BEGIN_REQUEST, etc.
long id; // id demande = id fastcgi
long lgCorps; // longueur corps du message (sans le padding)
long type; // type requete : OK ou ABORT
Dynamic param, dataIn, dataOut;
long error;
} modCtxFcgi;
enum {
FCGI_BEGIN_REQUEST = 1,
FCGI_ABORT_REQUEST = 2,
FCGI_END_REQUEST = 3,
FCGI_PARAMS = 4,
FCGI_STDIN = 5,
FCGI_STDOUT = 6,
/* role demande dans le BEGIN REQUEST */
FCGI_RESPONDER = 1,
FCGI_AUTHORIZER = 2,
FCGI_FILTER = 3,
/* code du "protocol status" lors du END REQUEST */
FCGI_REQUEST_COMPLETE = 0,
FCGI_CANT_MPX_CONN = 1,
FCGI_OVERLOADED = 2,
FCGI_UNKNOWN_ROLE = 3,
/* type requete en cours */
FCGI_REQUEST_OK = 0,
FCGI_REQUEST_ABORT = 1,
/* version prise en charge */
FCGI_VERSION = 1,
/* codes d'erreur */
FCGI_VERSION_UNSUPPORTED = 1,
FGCI_MESSAGETYPE_UNSUPPORTED = 2,
FGCI_PARAMETER_INCORRECT = 3,
/* codes retour */
FCGI_REQUEST_ERROR = -1,
FCGI_REQUEST_INPROGRESS = 0,
FCGI_REQUEST_AVAILABLE = 1
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
WAPIDECL void Init(env * e, modCtxFcgi * ctx);
WAPIDECL void End(env * e, modCtxFcgi * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxFcgi * ctx, Dynamic * data);
WAPIDECL long MakeResponse(env * e, modCtxFcgi * ctx, long cr, Dynamic * reponse);
/*
exemples :
1. A simple request with no data on stdin, and a successful response:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2. Similar to example 1, but this time with data on stdin. The Web server chooses to send the parameters using more FCGI_PARAMS records than before:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3. Similar to example 1, but this time the application detects an error. The application logs a message to stderr, returns a page to the client, and returns non-zero exit status to the Web server. The application chooses to send the page using more FCGI_STDOUT records:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4. Two instances of example 1, multiplexed onto a single connection. The first request is more difficult than the second, so the application finishes the requests out of order:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
*/
+105 -330
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -20,361 +20,136 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
enum {
/* types de requete FCGI */
FCGI_BEGIN_REQUEST = 1,
FCGI_ABORT_REQUEST = 2,
FCGI_END_REQUEST = 3,
FCGI_PARAMS = 4,
FCGI_STDIN = 5,
FCGI_STDOUT = 6,
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
/* demande dans le BEGIN REQUEST */
FCGI_RESPONDER = 1,
FCGI_AUTHORIZER = 2,
FCGI_FILTER = 3,
#include "langage.h"
#include "dynamic.h"
/* code du "protocl status" lors du END REQUEST */
FCGI_REQUEST_COMPLETE = 0,
FCGI_CANT_MPX_CONN = 1,
FCGI_OVERLOADED = 2,
FCGI_UNKNOWN_ROLE = 3,
#include "fcgi.h"
/* codes d'erreurs du module */
WFC_OK = 0, /* continuer a lire */
WFC_ERR = 1,
WFC_KEEPALIVE = 2,
WFC_REPONDRE = 3
};
typedef struct {
int error; // dernier code erreur specifique au module
//*** a completer selon le besoin du module
modCtxFcgi ctxFcgi;
} modEtat;
/* Descritpion du message en cours ; id = 0 si aucun en cours */
struct {
octet vers;
ent16 id;
octet keepAlive;
octet req; /* requete en cours : entete lue, attente message */
ent16 lg; /* longueur message apres entete a lire */
Dynamic param;
Dynamic dataIn;
Dynamic dataOut;
} fcgiReq;
/* mettre ici les codes d'erreurs specifiques au module */
/* codes a passer a la fonction setError */
#define EXMOD_xxx 1
/* enchainement des appels a faire
- lecture : lire la socket et appeler readFcgi
si retour = ERR, sortir en erreur
si retour = OK, continuer a lire (mettre a la fin du message en cours) et appeler readFcgi
si retour = REPONDRE, envoyer la reponse
- calculer la reponse, lire les donnes avec getFcgiDataIn
- ecriture : appel writeFcgi pour formater la sortie et lire le resultat avec getFcgiDataOut
si retour = ERR, sortir en erreur
ecrire tout le message dans la socket, quand ok :
appel writeFcgi pour formater la suite (blocs de 65535 octets max) etc. Quand fini :
appel writeEndFcgi pour formater le message de fin et lire le resultat avec getFcgiDataOut
ecrire le message de fin sur la socket
si retour = OK, fermer la socket
si retour = KEEPALIVE, garder la socket ouverte pour la suite
- si sortie en erreur ou erreur socket, fermer la socket
*/
long getFcgiDataIn(env * e, Dynamic * msg)
static int setError(modEtat * p, int err)
{
if(fcgiReq.vers != 0 && fcgiReq.id != 0)
{
/* copie de param + dataIn dans msg : msg<1,x> = nom param, msg<2,x> = valeur param, msg<3> contenu requete */
dynSetLen(e, msg, 0);
dynConcat(e, msg, &fcgiReq.param);
dynStoreSz(e, msg, 3, "", 0);
dynConcat(e, msg, &fcgiReq.dataIn);
return WFC_OK;
}
else
return WFC_ERR; /* TODO pas de requete en cours */
if(p != NULL)
p->error = err;
return err == OK ? OK : EX_MODERR;
}
long getFcgiDataOut(env * e, Dynamic * msg)
{
if(fcgiReq.vers != 0 && fcgiReq.id != 0)
{
/* copie de dataOut dans msg */
dynSetLen(e, msg, 0);
dynConcat(e, msg, &fcgiReq.dataOut);
return WFC_OK;
}
else
return WFC_ERR; /* TODO pas de requete en cours */
}
#ifdef WINLIB
/* Sous Windows, export de la fonction de base au sein d'une DLL : 1 module = 1 DLL */
__declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
#endif
long readFcgi(env * e, Dynamic * msg)
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* "decodage" du message fcgi en entree */
if(msg->mLg < 8)
return WFC_RR; /* TODO longueur message incorrecte */
if(msg->ptr[0] != 1)
return WFC_ERR; /* TODO version message incorrecte (version 1 supportee uniquement) */
/* */
/* selon le type de message, controles */
if(fcgiReq.id != 0 && fcgiReq.vers != 0 && fcgi.req != 0)
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
// - - - - - - - - - - - - - - - - - - - -
if(etat == NULL)
return EX_MODPARAM;
else
p_etat = (modEtat *)(*etat); /* evite de la faire a chaque fonction */
//
if(param1 != NULL)
if(param1->type == VAR_PARAM)
param1 = (var *)param1->ptr; /* evite de le faire a chaque fonction */
if(param2 != NULL)
if(param2->type == VAR_PARAM)
param2 = (var *)param2->ptr; /* evite de le faire a chaque fonction */
if(param3 != NULL)
if(param3->type == VAR_PARAM)
param3 = (var *)param3->ptr; /* evite de le faire a chaque fonction */
//
/* ----------------------------------------------------------------------------------------------- */
/* les 4 fonctions suivantes doivent toujours exister dans chaque module */
if(modFnIs(e, "init", 4))
{
/* entete requete lue => prise en charge du message */
if(msg->mLg < fcgiReq->lg)
// alloc ptr sur zone memoire pour memoriser l'etat du module
*etat = memalloc(e, sizeof(modEtat));
if(*etat == NULL)
exc = EX_MODETAT;
else
{
return WFC_OK; /* TODO message de la requete de longueur incorrecte : continuer a lire */
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//*** code specifique ici
Init(e, &p_etat->ctxFcgi);
//
}
if(fcgiReq.req == FCGI_BEGIN_REQUEST)
}
else if(modFnIs(e, "end", 3))
{
//*** code specifique ici
End(e, &p_etat->ctxFcgi);
//
// liberation specifique au module avant arret process
if(p_etat != NULL)
memfree(e, p_etat);
}
else if(modFnIs(e, "vers", 4))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(msg->ptr[0] == 0 && msg->ptr[1] == FCGI_RESPONDER)
{
/* ok, seul role pris en charge */
fcgiReq.keepAlive = msg->ptr[2];
fcgiReq.req = 0;
fcgiReq.lg = 0;
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
}
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
{
return WFC_ERR; /* TODO role non pris en charge */
}
}
if(fcgiReq.req == FCGI_PARAMS)
{
/* decoder le message pour maj fcgiReq.param <1,x> et <2,x> */
long pos = 0, lgnam, lgval, nb;
nb = dynDcount(e, &fcgiReq.param, 1, cFM, cVM);
for(; pos < fcgiReq->lg;)
{
if((lgnam = msg->ptr[pos]) > 127)
{
if(pos + 3 >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
lgnam = (lgnam & 127) << 24 + msg->ptr[pos + 1] << 16 + msg->ptr[pos + 2] << 8 + msg->ptr[pos + 3];
pos += 3;
}
if(++pos >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
if((lgval = msg->ptr[pos]) > 127)
{
if(pos + 3 >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
lgval = (lgval & 127) << 24 + msg->ptr[pos + 1] << 16 + msg->ptr[pos + 2] << 8 + msg->ptr[pos + 3];
pos += 3;
}
if(pos + lgnam + lgval >= fcgiReq->lg)
{
return WFC_ERR; /* TODO erreur dans le format des parametres */
}
/* TODO copier name/valeur dans <param> ; utilise fcgiReq.dataOut comme var. temp */
dynCtrl(e, &fcgiReq.dataOut, lgnam + lgval + 2, FALSE);
nb++;
pos++;
memcopie(fcgiReq.dataOut.ptr, msg->ptr + pos, lgnam);
dynSetLen(e, &fcgiReq.dataOut, lgnam);
dynStore(e, &fcgiReq.dataOut, 1, nb, fcgiReq.dataOut, cFM, cVM);
pos += lgnam
memcopie(fcgiReq.dataOut.ptr, msg->ptr + pos, lgval);
dynSetLen(e, &fcgiReq.dataOut, lgval);
dynStore(e, &fcgiReq.dataOut, 2, nb, fcgiReq.dataOut, cFM, cVM);
pos += lgval;
}
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return OK;
}
if(fcgiReq.req == FCGI_STDIN)
{
dynConcatSz(e, &fcgiReq.dataIn, msg->mPtr, fcgiReq.lg);
/* supprimer de msg les <lg> premiers cars */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
if(msg->ptr[1] == FCGI_BEGIN_REQUEST)
else if(modFnIs(e, "error", 5))
{
if(fcgiReq.id != 0 || fcgiReq.vers != 0)
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
return WFC_ERR; /* TODO une autre requete deja en cours ; envoyer une requete END REQUEST avec prot.status FCGI_CANT_MPX_CONN (1) ? return OKCANTMPX */
if(param1->type == VAR_NUMBER)
param1->num = (ent64)(NUM_FACTEUR * p_etat->error);
else
exc = EX_MODPARAM; // bad type of parameter
}
fcgiReq.vers = msg->ptr[0];
fcgiReq.id = msg->ptr[2] << 8 + msg->ptr[3];
fcgiReq.req = FCGI_BEGIN_REQUEST;
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
dynSetLen(e, &fcgiReq.param, 0);
dynSetLen(e, &fcgiReq.dataIn, 0);
dynSetLen(e, &fcgiReq.dataOut, 0);
return WFC_OK;
}
else if(msg->ptr[1] == FCGI_PARAMS)
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param3->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
return WFC_ERR; /* TODO pas de requete en cours */
long cr = ExtractMessage(e, &p_etat->ctxFcgi, param1);
param2->num = cr * NUM_FACTEUR;
if(cr == FCGI_REQUEST_AVAILABLE)
dynSetAs(e, param3, &p_etat->ctxFcgi.dataIn);
}
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
if(fcgiReq.lg > 0)
fcgiReq.req = FCGI_PARAMS;
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
return WFC_OK;
}
else if(msg->ptr[1] == FCGI_STDIN)
{
if(fcgiReq.id == 0 && fcgiReq.vers == 0)
{
return WFC_ERR; /* TODO pas de requete en cours */
}
fcgiReq.lg = msg->ptr[4] << 8 + msg->ptr[5];
if(fcgiReq.lg > 0)
fcgiReq.req = FCGI_STDIN;
/* supprimer de msg les <8> premiers cars */
memcopie(msg->mPtr, msg->mPtr + 8, msg->mLg - 7); /* -8+1 pour copier le \0 de fin */
msg->mLg -= 8;
return (fcgiReq.lg == 0 ? WFC_REPONDRE : WFC_OK); /* requete STDIN vide = fin de la demande : reponse a faire */
}
/* ----------------------------------------------------------------------------------------------- */
else
{
return WFC_ERR; /* TODO type requete non prise en charge */
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
}
//
return exc;
}
long writeFcgi(env * e, Dynamic * msg)
{
/* codage du message fcgi pour envoi : se trouvera dans "fcgi.dataOut" */
if(fcgiReq.vers != 0 && fcgiReq.id != 0 && fcgiReq.req == 0 && fcgiReq.lg == 0) ; else
{
return WFC_ERR; /* etat de la requete ne permet pas d'envoyer */
}
/* envoyer par bloc de 65535 cars max, en multiple de 8 */
if(msg->mLg > 65535)
fcgiReq.lg = 65535;
else
fcgiReq.lg = msg->mLg;
dynCtrl(e, &fcgiReq.dataOut, fcgiReq.lg + 16, FALSE); /* TODO test si ok ; 16 pour s'eviter des calculs ici... */
fcgiReq.dataOut.ptr[0] = fcgiReq.vers;
fcgiReq.dataOut.ptr[1] = FCGI_STDOUT;
fcgiReq.dataOut.ptr[2] = fcgiReq.id >> 8;
fcgiReq.dataOut.ptr[3] = fcgiReq.id & 255;
fcgiReq.dataOut.ptr[4] = fcgiReq.lg >> 8;
fcgiReq.dataOut.ptr[5] = fcgiReq.lg & 255;
fcgiReq.dataOut.ptr[6] = (8 - (fcgiReq.lg % 8)) & 7;
fcgiReq.dataOut.ptr[7] = 0;
/* */
memcopie(fcgiReq.dataOut.mPtr + 8, msg->mPtr, fcgiReq.lg);
fcgiReq.dataOut.mLg = fcgireq.lg + 8 + fcgiReq.dataOut.ptr[6];
/* a supprimer du debut de msg */
memcopie(msg->mPtr, msg->mPtr + fcgiReq.lg, msg->mLg - fcgiReq.lg + 1); /* -fcgiReq.lg+1 pour copier le \0 de fin */
msg->mLg -= fcgiReq.lg;
return WFC_OK;
}
long writeEndFcgi(env * e)
{
/* codage du message fcgi pour envoi : se trouvera dans "fcgi.dataOut" */
if(fcgiReq.vers != 0 && fcgiReq.id != 0 && fcgiReq.req == 0 && fcgiReq.lg == 0) ; else
{
return WFC_ERR; /* etat de la requete ne permet pas d'envoyer */
}
/* */
fcgiReq.dataOut.ptr[0] = fcgiReq.vers;
fcgiReq.dataOut.ptr[1] = FCGI_END_REQUEST;
fcgiReq.dataOut.ptr[2] = fcgiReq.id >> 8;
fcgiReq.dataOut.ptr[3] = fcgiReq.id & 255;
fcgiReq.dataOut.ptr[4] = 0;
fcgiReq.dataOut.ptr[5] = 8;
fcgiReq.dataOut.ptr[6] = 0; /* padding multiple de 8 */
fcgiReq.dataOut.ptr[7] = 0;
/* */
fcgiReq.dataOut.ptr[8] = 0; /* statut applicatif */
fcgiReq.dataOut.ptr[9] = 0;
fcgiReq.dataOut.ptr[10] = 0;
fcgiReq.dataOut.ptr[11] = 0;
fcgiReq.dataOut.ptr[12] = 0; /* protocole status, 0 = OK, 1 = FCGI_CANT_MPX_CONN */
fcgiReq.dataOut.ptr[13] = 0;
fcgiReq.dataOut.ptr[14] = 0;
fcgiReq.dataOut.ptr[15] = 0;
/* */
fcgiReq.dataOut.mLg = 16;
return (fcgiReq.keepAlive ? WFC_KEEPALIVE : WFC_OK);
}
long writeCantMpxFcgi(env * e, octet vers, ent16 id)
{
/* */
fcgiReq.dataOut.ptr[0] = vers;
fcgiReq.dataOut.ptr[1] = FCGI_END_REQUEST;
fcgiReq.dataOut.ptr[2] = id >> 8;
fcgiReq.dataOut.ptr[3] = id & 255;
fcgiReq.dataOut.ptr[4] = 0;
fcgiReq.dataOut.ptr[5] = 8;
fcgiReq.dataOut.ptr[6] = 0; /* padding multiple de 8 */
fcgiReq.dataOut.ptr[7] = 0;
/* */
fcgiReq.dataOut.ptr[8] = 0; /* statut applicatif */
fcgiReq.dataOut.ptr[9] = 0;
fcgiReq.dataOut.ptr[10] = 0;
fcgiReq.dataOut.ptr[11] = 0;
fcgiReq.dataOut.ptr[12] = 1; /* protocole status, 0 = OK, 1 = FCGI_CANT_MPX_CONN */
fcgiReq.dataOut.ptr[13] = 0;
fcgiReq.dataOut.ptr[14] = 0;
fcgiReq.dataOut.ptr[15] = 0;
/* */
fcgiReq.dataOut.mLg = 16;
return WFC_OK;
}
/* pour appel depuis un serveur http ("client" genere des requetes pour l'application fastcgi)
ou gestion de l'application fastcgi (type module php) "serveur" avec requetes entrantes (accept)
et multiplexage ou non des requetes (sur ID ; autorisation ou non)
recupere un socket existant (comme sslMod)
*
* exemple de flux
* FCGI_BEGIN_REQUEST, 1,1, FCGI_RESPONDER/1, 0 ou 1 CGI_KEEP_CONN ("keep alive")
* FCGI_PARAMS, 1,4, "\0xB\0x2SERVER_PORT80\0xB\0xESERVER_ADDR199.170.183.42 ... "
* FCGI_PARAMS, 1,4, ""
* FCGI_STDIN, 1,5, "quantity=100&item=3047936"
* FCGI_STDIN, 1,5, "" ==> marque la fin de la question et attend de la reponse (au moins ce message apres BEGIN REQUEST)
*
* FCGI_STDOUT, 1,6, "Content-type: text/html\r\n\r\n<html>\n<head> ... "
* FCGI_STDOUT, 1,6, ""
* FCGI_END_REQUEST, 1,3, 0, FCGI_REQUEST_COMPLETE/0
*
* FastCGI
*---------
* chaque requete : entete 8 octets + contenu (multiple de 8)
* vers | type | MSB id LSB | MSB lg LSB |padlg | reser| requete
* +------+------+------+------+------+------+------+------+-----......------+
* 1 lg+padlg = multiple de 8
* type
* 1:BEGIN 3:END 4:PARAMS (paires Name/Value) 5:STDIN (brut) 6:STDOUT (brut)
*
* contenu requete pour chaque type
* 1: MSB role LSB |flags | reserve
* +------+------+------+------+------+------+------+------+ lg = 8
* role -> responder = 1 ; flags -> 0/1 : keep connection alive
* si keep alive = 1 avec fork, a la fin de la reponse, garder la socket ouverte
*
* 3: MSB . . status . . . LSB |pro st| reserve
* +------+------+------+------+------+------+------+------+ lg = 8
* pro st -> protocol status -> complete = 0
* status = statut applicatif (?)
*
* 4: lg nam|lg val| name | value |
* +------+------+--.....----+--...----+
* avec lg name et lg value < 127
* si > 127, encodage sur 4 octets MSB x x LSB ; lg maxi = 2^31-1 (bit 31 non significatif = 1)
*
* 5/6: contenu "libre"
*
*/
+388
View File
@@ -0,0 +1,388 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "fcgi.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
static long LireParametre(env * e, modCtxFcgi * ctx)
{
long pos = 0, len = ctx->dataOut.mLg;
octet * ptr = (octet *)ctx->dataOut.mPtr;
while(pos < len)
{
octet lgNom, lgVal;
long lgNomLong, lgValLong;
lgNom = ptr[pos++];
if(lgNom > 127)
{
if(pos + 3 > len)
return DYN_ERR; /* erreur */
lgNomLong = lgNom & 127;
lgNomLong = lgNomLong * 256 + ptr[pos++];
lgNomLong = lgNomLong * 256 + ptr[pos++];
lgNomLong = lgNomLong * 256 + ptr[pos++];
}
else
lgNomLong = lgNom;
//
if(pos >= len)
return DYN_ERR; /* erreur */
lgVal = ptr[pos++];
if(lgVal > 127)
{
if(pos + 3 > len)
return DYN_ERR; /* erreur */
lgValLong = lgVal & 127;
lgValLong = lgValLong * 256 + ptr[pos++];
lgValLong = lgValLong * 256 + ptr[pos++];
lgValLong = lgValLong * 256 + ptr[pos++];
}
else
lgValLong = lgVal;
//
if(pos + lgNomLong + lgValLong > len)
return DYN_ERR; /* erreur */
// lire les lgNomLong octets du nom du parametre et maj dans mParam<1,x>
// et lire les lgValLong octets de la valeur du parametre et maj dans mParam<2,x>
dynInsSz(e, &ctx->param, 1, 1, (char *)(ptr + pos), lgNomLong, cFM, cVM);
pos += lgNomLong;
dynInsSz(e, &ctx->param, 2, 1, (char *)(ptr + pos), lgValLong, cFM, cVM);
pos += lgValLong;
}
return OK;
}
static long EcrireEntete(env * e, modCtxFcgi * ctx, octet type, long id, long lg, long * lgpad)
{
if(dynCtrl(e, &ctx->dataOut, ctx->dataOut.mLg + 8, TRUE) != DYN_OK)
return DYN_ERR;
/* */
octet * ptr = (octet *)(ctx->dataOut.ptr + ctx->dataOut.mLg);
*lgpad = (8 - (lg % 8)) % 8;
dynSetLen(e, &ctx->dataOut, ctx->dataOut.mLg + 8);
/* */
*ptr++ = FCGI_VERSION;
*ptr++ = type;
*ptr++ = (id / 256) % 256; // MSB id
*ptr++ = id % 256; // LSB id
*ptr++ = (lg / 256) % 256; // MSB lg
*ptr++ = lg % 256; // LSB lg
*ptr++ = *lgpad;
*ptr = 0;
return OK;
}
static long EcrireCorps(env * e, modCtxFcgi * ctx, octet type, long crApplicatif, octet status)
{
switch(type)
{
case FCGI_END_REQUEST:
{
if(dynCtrl(e, &ctx->dataOut, ctx->dataOut.mLg + 8, TRUE) != DYN_OK)
return DYN_ERR;
//
octet * ptr = (octet *)(ctx->dataOut.ptr + ctx->dataOut.mLg);
dynSetLen(e, &ctx->dataOut, ctx->dataOut.mLg + 8);
//
*(ptr + 3) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 2) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 1) = crApplicatif % 256;
crApplicatif /= 256;
*(ptr + 0) = crApplicatif % 256;
ptr += 4;
*ptr++ = status;
*ptr++ = 0;
*ptr++ = 0;
*ptr++ = 0;
break;
}
}
return OK;
}
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxFcgi * ctx)
{
ctx->keepAlive = 0;
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->typeMessage = 0; // BEGIN_REQUEST, etc.
ctx->id = 0; // id demande = id fastcgi
ctx->lgCorps = 0; // longueur corps du message
ctx->type = 0;
ctx->error = 0;
/* */
dynInit(e, &ctx->param, DYN_LGMIN);
dynInit(e, &ctx->dataIn, DYN_LGMIN);
dynInit(e, &ctx->dataOut, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxFcgi * ctx)
{
dynFree(e, &ctx->param);
dynFree(e, &ctx->dataIn);
dynFree(e, &ctx->dataOut);
}
WAPIDECL long ExtractMessage(env * e, modCtxFcgi * ctx, Dynamic * data)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
while(data->mLg > 0)
{
if(ctx->resteALireEntete == -1)
{
// entete fcgi attendue
if(data->mLg < 8)
return FCGI_REQUEST_INPROGRESS; /* attndre les donnees suivantes */
octet * ptr = (octet *)data->ptr;
octet vers = *ptr++;
ctx->typeMessage = *ptr++;
ctx->id = (*ptr++) * 256;
ctx->id += *ptr++;
long lg = (*ptr++) * 256;
lg += *ptr++;
long lgpad = *ptr;
dynCut(e, data, 8);
if(vers != FCGI_VERSION)
{
ctx->error = FCGI_VERSION_UNSUPPORTED;
return FCGI_REQUEST_ERROR; // erreur : version non prise en charge
}
//
ctx->resteALireEntete = 0;
ctx->lgCorps = lg;
ctx->resteALireCorps = lg + lgpad;
//
if(ctx->typeMessage == FCGI_BEGIN_REQUEST)
{
dynSetLen(e, &ctx->dataIn, 0);
dynSetLen(e, &ctx->param, 0);
}
if(ctx->typeMessage == FCGI_STDIN && ctx->resteALireCorps == 0)
{
// toutes les données de la requete ont ete recues : traiter puis envoyer reponse
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->type = FCGI_REQUEST_OK;
return FCGI_REQUEST_AVAILABLE;
}
if(ctx->typeMessage == FCGI_ABORT_REQUEST)
{
// forcer une reponse END_REQUEST
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
ctx->type = FCGI_REQUEST_ABORT;
return FCGI_REQUEST_AVAILABLE;
}
if(ctx->resteALireCorps == 0)
{
// message vide : attendre de nouveau l'entete
ctx->resteALireEntete = -1;
ctx->resteALireCorps = -1;
}
continue;
}
if(ctx->resteALireCorps > 0)
{
if(data->mLg < ctx->resteALireCorps)
return FCGI_REQUEST_INPROGRESS; // attendre : tout n'est pas recu
//
dynLet(e, &ctx->dataOut, data->mPtr, ctx->lgCorps); // ne pas prendre le padding...
dynCut(e, data, ctx->resteALireCorps);
ctx->resteALireCorps = 0;
ctx->resteALireEntete = -1;
//
switch(ctx->typeMessage)
{
case FCGI_BEGIN_REQUEST:
// verifier role = FCGI_RESPONDER ? si oui et erreur, forcer une reponse ABORT
ctx->keepAlive = (ctx->dataOut.mPtr[2] == 1);
// nota : durant les tests avec nginx, cela ne fonctionne pas : nginx ne reutilise pas la derniere socket ! Flag a remettre lors du EndRequest ?
break;
case FCGI_STDIN:
dynConcat(e, &ctx->dataIn, &ctx->dataOut);
break;
case FCGI_PARAMS:
// maj param sur attributs 1 & 2 en multi-valeurs (lu de dataOut)
if(LireParametre(e, ctx) != OK)
{
ctx->error = FGCI_PARAMETER_INCORRECT;
return FCGI_REQUEST_ERROR;
}
break;
default:
ctx->error = FGCI_MESSAGETYPE_UNSUPPORTED;
return FCGI_REQUEST_ERROR;
break;
}
}
}
return FCGI_REQUEST_INPROGRESS;
}
WAPIDECL long MakeResponse(env * e, modCtxFcgi * ctx, long cr, Dynamic * reponse)
{
long lgReponse = reponse->mLg, lgpad;
long debut = 0;
dynSetLen(e, &ctx->dataOut, 0);
/* */
if(ctx->type == FCGI_REQUEST_OK)
{
while (lgReponse > 0)
{
long lg;
if(lgReponse > 65535)
lg = 65535;
else
lg = lgReponse;
//
if(EcrireEntete(e, ctx, FCGI_STDOUT, ctx->id, lg, &lgpad) != OK)
return DYN_ERR;
dynConcatSz(e, &ctx->dataOut, reponse->mPtr + debut, lg);
if(lgpad > 0)
{
char pad[8] = "0000000";
pad[(lgpad) % 8] = 0;
dynConcatSz(e, &ctx->dataOut, pad, DYN_LGNONE);
}
//
lgReponse -= lg;
debut += lg;
}
// envoyer STDOUT de longueur nulle
if(EcrireEntete(e, ctx, FCGI_STDOUT, ctx->id, 0, &lgpad) != OK) // a envoyer si ABORT_REQUEST demande par le serveur Web ?
return DYN_ERR;
} // sinon forcement ABRT = que le END_REQUEST
// envoyer END_REQUEST
if(EcrireEntete(e, ctx, FCGI_END_REQUEST, ctx->id, 8, &lgpad) != OK)
return DYN_ERR;
if(EcrireCorps(e, ctx, FCGI_END_REQUEST, cr, FCGI_REQUEST_COMPLETE) != OK)
return DYN_ERR;
//
// reponse mis a jour au format fcgi
dynSetAs(e, reponse, &ctx->dataOut);
return OK;
}
/*
exemples :
1. A simple request with no data on stdin, and a successful response:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
2. Similar to example 1, but this time with data on stdin. The Web server chooses to send the parameters using more FCGI_PARAMS records than before:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SER"}
{FCGI_PARAMS, 1, "VER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, "quantity=100&item=3047936"}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
3. Similar to example 1, but this time the application detects an error. The application logs a message to stderr, returns a page to the client, and returns non-zero exit status to the Web server. The application chooses to send the page using more FCGI_STDOUT records:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, 0}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n<ht"}
{FCGI_STDERR, 1, "config error: missing SI_UID\n"}
{FCGI_STDOUT, 1, "ml>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_STDERR, 1, ""}
{FCGI_END_REQUEST, 1, {938, FCGI_REQUEST_COMPLETE}}
4. Two instances of example 1, multiplexed onto a single connection. The first request is more difficult than the second, so the application finishes the requests out of order:
{FCGI_BEGIN_REQUEST, 1, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 1, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_PARAMS, 1, ""}
{FCGI_BEGIN_REQUEST, 2, {FCGI_RESPONDER, FCGI_KEEP_CONN}}
{FCGI_PARAMS, 2, "\013\002SERVER_PORT80\013\016SERVER_ADDR199.170.183.42 ... "}
{FCGI_STDIN, 1, ""}
{FCGI_STDOUT, 1, "Content-type: text/html\r\n\r\n"}
{FCGI_PARAMS, 2, ""}
{FCGI_STDIN, 2, ""}
{FCGI_STDOUT, 2, "Content-type: text/html\r\n\r\n<html>\n<head> ... "}
{FCGI_STDOUT, 2, ""}
{FCGI_END_REQUEST, 2, {0, FCGI_REQUEST_COMPLETE}}
{FCGI_STDOUT, 1, "<html>\n<head> ... "}
{FCGI_STDOUT, 1, ""}
{FCGI_END_REQUEST, 1, {0, FCGI_REQUEST_COMPLETE}}
---------
FastCGI
---------
chaque requete : entete 8 octets + contenu (multiple de 8)
vers | type | MSB id LSB | MSB lg LSB |padlg | reser| requete
+------+------+------+------+------+------+------+------+-----......------+
1 lg+padlg = multiple de 8
type
1:BEGIN 3:END 4:PARAMS (paires Name/Value) 5:STDIN (brut) 6:STDOUT (brut)
contenu requete pour chaque type
1: MSB role LSB |flags | reserve
+------+------+------+------+------+------+------+------+ lg = 8
role -> responder = 1 ; flags -> 0/1 : keep connection alive
si keep alive = 1 avec fork, a la fin de la reponse, garder la socket ouverte
3: MSB . . status . . . LSB |pro st| reserve
+------+------+------+------+------+------+------+------+ lg = 8
pro st -> protocol status -> complete = 0
status = statut applicatif (?)
4: lg nam|lg val| name | value |
+------+------+--.....----+--...----+
avec lg name et lg value < 127
si > 127, encodage sur 4 octets MSB x x LSB ; lg maxi = 2^31-1 (bit 31 non significatif = 1)
5/6: contenu "libre"
*/
+72 -21
View File
@@ -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)
{
@@ -114,13 +118,18 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
}
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_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(modFnIs(e, "error", 5))
{
@@ -138,14 +147,56 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
}
}
/* ============================================================================================= */
else if(modFnIs(e, "create", 6))
else if(modFnIs(e, "rename", 6))
{
// todo...
// test
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
p_etat->error++;
printf("mod create %d\n", p_etat->error);
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
if(rename(param1->mPtr, param2->mPtr))
exc = setError(p_etat, EXMOD_REMOVE);
}
}
/* ----------------------------------------------------------------------------------------------- */
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))
@@ -158,7 +209,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
else
{
if(dynRead(e, param2, param1->mPtr) != DYN_OK)
exc = setError(p_etat, 1);
exc = setError(p_etat, EXMOD_READ);
}
}
/* ----------------------------------------------------------------------------------------------- */
@@ -177,11 +228,11 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
if((fic = fopen(param1->mPtr, "w")) == 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(fwrite(param2->mPtr, param2->mLg, 1, fic) != 1) /* retourne le nb de blocs ecrits, pas lenb d'octets !! */
exc = setError(p_etat, 1); /* erreur generique : lire la vraie erreur ailleurs */
exc = setError(p_etat, EXMOD_WRITE); /* erreur generique : lire la vraie erreur ailleurs */
fclose(fic);
}
}
@@ -204,11 +255,11 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#else
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 */
@@ -231,7 +282,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
#ifdef UNIX
DIR * rep = NULL;
if((rep = opendir(param1->mPtr)) == NULL)
exc = setError(p_etat, 1); /* todo vraie erreur */
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
else
{
dynSetLen(e, param1, 0); // idem raz
@@ -268,7 +319,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
FindClose(hFind);
}
else
exc = setError(p_etat, 1); /* todo vraie erreur */
exc = setError(p_etat, EXMOD_ACCESS); /* todo vraie erreur */
#endif
}
}
+3 -3
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;
@@ -251,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()
+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
+5 -209
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
@@ -350,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);
@@ -364,7 +160,7 @@ 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);//
+226 -76
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -30,10 +30,11 @@
#include "langage.h"
#include "dynamic.h"
#include "lex.c"
#include "lex.h"
#include "instr.h"
#include "rep.h"
#include "arg.c"
#include "convert.h"
enum {
WVERS = 1, /* version du compilateur w et donc du code compile */
@@ -98,7 +99,13 @@ Dynamic dercode;/* pour la gestion des variables de hash a gauche du signe " = "
long setfld; /* pour gestion let x{1} et let x{1,1} : 1 ou 2 si field ou value */
long setsubstr; /* pour gestion let x[1,2] et x{3,4}[1,2] : 1 si substr avec 2 params */
Dynamic forend,forinc; /* variables pour le code asm des boucles foreach numeriques */
Dynamic forend,forinc; /* variables pour le code asm des boucles foreach numeriques */
Dynamic varparam; /* contient les variables passees en parametre a une sub : interdire ceratins formes d'appel pour eviter plus tard des erreurs de pointeur */
int doVarParam; /* booleen pour activer dans variable() la memo des variables dans varparam */
int derPvah; /* dans un passage de parametre, indique si la derniere operation PVAR/PVAH/PVAI est bien PVAH */
int typeof_; /* gestion du cas "typeof var" dans terme() */
/* -------------------- */
ent64 lap = 0; /* calcul temps du programme (hors init, alloc et free), en ms */
@@ -139,11 +146,13 @@ long init(env * e)
dynInit(e, &srcdbg, 0);
dynInit(e, &forend, 0);
dynInit(e, &forinc, 0);
dynInit(e, &varparam, 0);
iPrio = 0;
iImbriPrio = 1;
numNiv = 0;
idNiv = 0;
numlig = 0;
doVarParam = 0;
return OK; /* TODO controles */
}
@@ -160,6 +169,7 @@ void fin(env * e)
dynFree(e, &srcdbg);
dynFree(e, &forend);
dynFree(e, &forinc);
dynFree(e, &varparam);
}
long rg(env * e, Dynamic * regles, char * nom, Dynamic * tmp)
@@ -182,11 +192,12 @@ sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,2
return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30
continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40
new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50
neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60
format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70
lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80
indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90
multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99
neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60
search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70
gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80
endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90
numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100
modsep,101,other,102
*/
struct {
ent16 blank,comment,begin,background,library,end,except,throw,catch,include;
@@ -194,11 +205,12 @@ struct {
ent16 return_,returnon,loop,endloop,foreach,in,like,endfor,break_,breakon;
ent16 continue_,continueon,nop,part,echonl,echo,input,declare,let,delet;
ent16 new,class,this,parent,hold,precision,setsep,int_,frac,abs;
ent16 neg,round,type,len,count,dcount,field,index,search,change;
ent16 format,insert,remove,tonum,tostring,equal,diff,gt,lt,gte;
ent16 lte,and,or,not,beginpar,endpar,beginh,endh,begins,ends;
ent16 indirect,typeof_,stringdq,stringq,ident,varsys,numberdec,numberint,minus,plus;
ent16 multiply,divide,divident,modulo,concat,listesep,identsep,modsep,other;
ent16 neg,round,sqrt,exp,type,len,count,dcount,field,index;
ent16 search,sortedsearch,change,format,insert,remove,tonum,tostring,equal,diff;
ent16 gt,lt,gte,lte,and,or,not,beginpar,endpar,beginh;
ent16 endh,begins,ends,indirect,typeof_,stringdq,stringq,ident,varsys,numberdec;
ent16 numberint,minus,plus,multiply,divide,divident,modulo,concat,listesep,identsep;
ent16 modsep,other;
} r;
/* les 2 fonctions fictives ci dessous doivent avoir un numero < 512 et > au max de "r" ci-dessus */
/* servent a gerer la notation x{1,2}[3,4] */
@@ -269,15 +281,18 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
/* */
r.neg = rg(e, regles, "neg", tmp);
r.round = rg(e, regles, "round", tmp);
r.sqrt = rg(e, regles, "sqrt", tmp);
r.exp = rg(e, regles, "exp", tmp);
r.type = rg(e, regles, "type", tmp);
r.len = rg(e, regles, "len", tmp);
r.count = rg(e, regles, "count", tmp);
r.dcount = rg(e, regles, "dcount", tmp);
r.field = rg(e, regles, "field", tmp);
r.index = rg(e, regles, "index", tmp);
r.search = rg(e, regles, "search", tmp);
r.change = rg(e, regles, "change", tmp);
/* */
r.search = rg(e, regles, "search", tmp);
r.sortedsearch = rg(e, regles, "sortedsearch", tmp);
r.change = rg(e, regles, "change", tmp);
r.format = rg(e, regles, "format", tmp);
r.insert = rg(e, regles, "insert", tmp);
r.remove = rg(e, regles, "remove", tmp);
@@ -285,10 +300,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.tostring = rg(e, regles, "tostring", tmp);
r.equal = rg(e, regles, "equal", tmp);
r.diff = rg(e, regles, "diff", tmp);
/* */
r.gt = rg(e, regles, "gt", tmp);
r.lt = rg(e, regles, "lt", tmp);
r.gte = rg(e, regles, "gte", tmp);
/* */
r.lte = rg(e, regles, "lte", tmp);
r.and = rg(e, regles, "and", tmp);
r.or = rg(e, regles, "or", tmp);
@@ -296,10 +311,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.beginpar = rg(e, regles, "beginpar", tmp);
r.endpar = rg(e, regles, "endpar", tmp);
r.beginh = rg(e, regles, "beginh", tmp);
/* */
r.endh = rg(e, regles, "endh", tmp);
r.begins = rg(e, regles, "begins", tmp);
r.ends = rg(e, regles, "ends", tmp);
/* */
r.indirect = rg(e, regles, "indirect", tmp);
r.typeof_ = rg(e, regles, "typeof", tmp);
r.stringdq = rg(e, regles, "stringdq", tmp);
@@ -307,10 +322,10 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.ident = rg(e, regles, "ident", tmp);
r.varsys = rg(e, regles, "varsys", tmp);
r.numberdec = rg(e, regles, "numberdec", tmp);
/* */
r.numberint = rg(e, regles, "numberint", tmp);
r.minus = rg(e, regles, "minus", tmp);
r.plus = rg(e, regles, "plus", tmp);
/* */
r.multiply = rg(e, regles, "multiply", tmp);
r.divide = rg(e, regles, "divide", tmp);
r.divident = rg(e, regles, "divident", tmp);
@@ -318,6 +333,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
r.concat = rg(e, regles, "concat", tmp);
r.listesep = rg(e, regles, "listesep", tmp);
r.identsep = rg(e, regles, "identsep", tmp);
/* */
r.modsep = rg(e, regles, "modsep", tmp);
r.other = rg(e, regles, "other", tmp);
}
@@ -325,7 +341,7 @@ void init_reg(env * e, Dynamic * regles, Dynamic * tmp)
long tok2number(env * e, ent64s * numb, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
{
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
*numb = dynToNumber(e, encours);
if(encours->mInternal != DYN_OK)
return TERM_ERR; /* TODO erreur de conversion numerique */
@@ -340,7 +356,7 @@ long tok2number(env * e, ent64s * numb, Dynamic * valex, Dynamic * tmp, Dynamic
long tok2string(env * e, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
{
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
/* enlever le premier et dernier car, et remplacer les blocs #XX par le caractere correspondant */
/* encours est nettoyee "sur elle meme" */
long lgec = 0;
@@ -400,8 +416,11 @@ long variable(env * e, Dynamic * resultat, Dynamic * valex, Dynamic * tmp, Dynam
if(tok != r.ident && tok != r.this && tok != r.parent)
return VAR_ERR;
//
if(typeof_)
dynConcatSz(e, resultat, "TYPO\n", 5); // aGauche vaut toujours 0 en mode typeof
//
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
dynConcatSz(e, resultat, "PVAR ", 5);
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\n", 1);
@@ -412,6 +431,11 @@ long variable(env * e, Dynamic * resultat, Dynamic * valex, Dynamic * tmp, Dynam
//printf("ident:%s niv:%ld liste:%s\n", encours->mPtr, nbNivIdent, nivIdent.mPtr);
return VAR_ERR; // creer une erreur specifique
}
if(doVarParam)
{
dynConcatSz(e, &varparam, sFM, 1);
dynConcat(e, &varparam, encours);
}
/* */
n++;
for(;;)
@@ -423,20 +447,36 @@ long variable(env * e, Dynamic * resultat, Dynamic * valex, Dynamic * tmp, Dynam
/* */
n++;
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
if(tok3 == r.identsep || tok3 == r.indirect || ! *aGauche) // si a droite du " = " : toujours PVAH/PVAI !
{
if(tok2 == r.count)
{
if(typeof_)
return VAR_ERR; // pas de hash.count en mode typeof : non autorise
dynConcatSz(e, resultat, "HCOU", 4);
}
else
{
if(tok == r.identsep)
{
dynConcatSz(e, resultat, "PVAH ", 5);
derPvah = 1;
}
else
{
dynConcatSz(e, resultat, "PVAI ", 5);
derPvah = 0;
if(doVarParam)
doVarParam = 2; // indique au moins une indirection dans les vars
}
dynConcat(e, resultat, encours);
/* */
if(doVarParam)
{
dynConcatSz(e, &varparam, sVM, 1);
dynConcat(e, &varparam, encours);
}
}
dynConcatSz(e, resultat, "\n", 1);
}
@@ -454,6 +494,8 @@ long variable(env * e, Dynamic * resultat, Dynamic * valex, Dynamic * tmp, Dynam
/* */
n++;
}
if(typeof_)
dynConcatSz(e, resultat, "PSHT\n", 5);
return VAR_OK;
}
@@ -502,7 +544,7 @@ long terme(env * e, ent16 t, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
{
/* verifier par rapport a la liste VARSYS */
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X"); /* encours contient "@VARSYSXXX" */
hex2str(e, tmp, encours); /* encours contient "@VARSYSXXX" */
dynLet(e, tmp, VARSYS, DYN_LGNONE);
if(dynLocateSz(e, tmp, encours->mPtr, ',', 1, ';') < 1)
ret = TERM_ERR;
@@ -519,9 +561,9 @@ long terme(env * e, ent16 t, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
tok = nreg(n);
return TERM_PAR;
}
if((t == r.abs || t == r.int_ || t == r.frac || t == r.neg ||
if((t == r.abs || t == r.int_ || t == r.frac || t == r.neg || t == r.sqrt || t == r.exp ||
t == r.type || t == r.round || t == r.tonum || t == r.tostring ||
t == r.len || t == r.count || t == r.not || t == r.typeof_ ||
t == r.len || t == r.count || t == r.not || t == r.sortedsearch ||
t == r.dcount || t == r.field || t == r.index || t == r.search ||
t == r.change || t == r.format || t == r.insert || t == r.remove ) && nreg(n+1) == r.beginpar)
{
@@ -551,13 +593,22 @@ long terme(env * e, ent16 t, Dynamic * valex, Dynamic * tmp, Dynamic * encours)
tok = nreg(n);
return TERM_ENDS;
}
typeof_ = FALSE;
if(t == r.typeof_)
{
typeof_ = TRUE;
n++;
tok = nreg(n);
}
dynSetLen(e, &trav, 0);
if(variable(e, &trav, valex, tmp, encours, &aGauche) == VAR_OK)
{
typeof_ = FALSE;
/* var ; n et tok sont deja a jour (positionne sur le prochain token) */
return TERM_VAR;
}
/* sinon erreur */
typeof_ = FALSE;
return ret;
}
@@ -638,6 +689,12 @@ long stack_fn(env * e, Dynamic * resultat, long fn, long nbParam)
if(fn == r.neg)
return nbParam != 1 ? -1 : dynConcatSz(e, resultat, "NEGN\n", DYN_LGNONE);
if(fn == r.sqrt)
return nbParam != 1 ? -1 : dynConcatSz(e, resultat, "SQRT\n", DYN_LGNONE);
if(fn == r.exp)
return nbParam != 2 ? -1 : dynConcatSz(e, resultat, "IEXP\n", DYN_LGNONE);
if(fn == r.not)
return nbParam != 1 ? -1 : dynConcatSz(e, resultat, "COMP NOT\n", DYN_LGNONE);
@@ -660,9 +717,6 @@ long stack_fn(env * e, Dynamic * resultat, long fn, long nbParam)
if(fn == r.count)
return nbParam != 2 ? -1 : dynConcatSz(e, resultat, "COUN\n", DYN_LGNONE);
if(fn == r.typeof_)
return nbParam != 1 ? -1 : dynConcatSz(e, resultat, "TEST\n", DYN_LGNONE); /* TODO dans langage.c !! */
if(fn == r.dcount)
{
if(nbParam == 1)
@@ -691,6 +745,14 @@ long stack_fn(env * e, Dynamic * resultat, long fn, long nbParam)
else
return dynConcatSz(e, resultat, (nbParam == 2 ? "SRCH\n" : "SCHS\n"), DYN_LGNONE);
}
if(fn == r.sortedsearch)
{
if(nbParam != 3 && nbParam != 4)
return -1;
else
return dynConcatSz(e, resultat, (nbParam == 3 ? "SSRC\n" : "SSCS\n"), DYN_LGNONE);
}
if(fn == r.change)
return nbParam != 3 ? -1 : dynConcatSz(e, resultat, "CHNG\n", DYN_LGNONE);
@@ -907,9 +969,12 @@ long expr(env * e, Dynamic * resultat, Dynamic * valex, Dynamic * tmp, Dynamic *
else if(termType == TERM_STR)
{
/* empiler le terme en assembleur <string> */
dynConcatSz(e, resultat, "PVAT\nDSET \"", DYN_LGNONE); /* TODO pbm " dans la chaine : quid ?? */
dynChange(e, encours, (char *)"\"", "#22", DYN_ALL);
dynChange(e, encours, (char *)" ", "#20", DYN_ALL); // car dans assembler.c, "trim(3)" de chaque ligne...
dynConcatSz(e, resultat, "PVAT\nDSET \"", DYN_LGNONE);
//dynChange(e, encours, (char *)"\"", "#22", DYN_ALL);
//dynChange(e, encours, (char *)" ", "#20", DYN_ALL);
/* mettre en hexa les cars "speciaux", dont <espace> 32/#20 car assembleur.c fait un trim,
" 34/#22 car instr DSET utilise les guillements - ne pas convertir # 35/#23 car sert a coder un car en hexa, mettre #35 pour utiliser le # !! */
dynCleanString(e, encours, (octet)35, (octet)126, TRUE); // TRUE convertit les octets hors intervalle en hexa #xx
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\"\nPSHV\n", DYN_LGNONE);
/* chercher ENDPAR */
@@ -1165,6 +1230,20 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynSetLen(e, &token, token.mLg + 4);
}
}
/* pour debug : */
if(numlig == -1)
{
printf("tokens");
for(ent16 ival = 1; ival <= nbval; ival++)
{
tok = (ent16)dynExtractSubFieldAsNumber(e, valex, 2, ival, tmp);
printf(":%d", tok);
}
dynSetAs(e, tmp, valex);
dynReplace(e, tmp, 254, ';');
dynReplace(e, tmp, 253, ',');
printf("\nvalex: %s\n", tmp->mPtr);
}
/* */
/* debut d'analyse des tokens de la ligne de source w */
long aGauche = 0;
@@ -1213,7 +1292,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
{
dynConcatSz(e, resultat, "\nPNAM ", DYN_LGNONE);
dynField(e, valex, tmp, 1, norig(n - 1), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X"); /* la longueur d'un ident (24 max) est controlee dans lex */
hex2str(e, tmp, encours); /* la longueur d'un ident (24 max) est controlee dans lex */
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\n", 1);
}
@@ -1252,7 +1331,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
{
dynConcatSz(e, resultat, "PARM ", DYN_LGNONE);
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X"); /* la longueur d'un ident (24 max) est controlee dans lex */
hex2str(e, tmp, encours); /* la longueur d'un ident (24 max) est controlee dans lex */
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\n", 1);
// ajout aux vars a controler
@@ -1384,6 +1463,8 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
printf("Erreur ligne %dc%s : nom fichier include incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
/* ne garder que les cars entre 33 et 126, car INCL n'est que informatif ici */
dynCleanString(e, encours, (octet)33, (octet)126, FALSE); // FALSE pour supprimer et ne pas convertir en hexa #xx
// include deja mis dans <source>, mis ici pour info dans le compile
dynConcatSz(e, resultat, "SRCL ", DYN_LGNONE);
dynConcatSz(e, resultat, Int64ToSz(e, numlig, FALSE, 0), DYN_LGNONE);
@@ -1422,6 +1503,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
ent64s numb;
if(tok2number(e, &numb, valex, tmp, encours) != TERM_NUM)
{
/* TODO : tester une variable + modif langage.c/assembler */
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : numero exception throw incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
@@ -1507,6 +1589,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
ent64s numb;
if(tok2number(e, &numb, valex, tmp, encours) != TERM_NUM)
{
/* TODO : tester une variable + modif langage.c/assembler */
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : numero part incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
@@ -1863,7 +1946,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynConcatSz(e, resultat, "SRCL ", DYN_LGNONE);
dynConcatSz(e, resultat, Int64ToSz(e, numlig, FALSE, 0), DYN_LGNONE);
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
dynConcatSz(e, resultat, "\nDECL ", DYN_LGNONE);
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\n", DYN_LGNONE);
@@ -1878,7 +1961,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
/* */
n++;
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
dynConcatSz(e, resultat, "DECL ", DYN_LGNONE);
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\n", DYN_LGNONE);
@@ -1976,7 +2059,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
//dynConcatSz(e, resultat, Int64ToSz(e, numlig, FALSE, 0), DYN_LGNONE);
//dynConcatSz(e, resultat, "\n", DYN_LGNONE);
//dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
//dynIconv(e, tmp, encours, "X");
//hex2str(e, tmp, encours);
//dynConcatSz(e, resultat, "SUBR ", DYN_LGNONE);
//dynConcat(e, resultat, encours);
//dynConcatSz(e, resultat, "\nBEXC\n", DYN_LGNONE);
@@ -1988,7 +2071,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
if(tok == r.ident)
{
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
dynConcatSz(e, resultat, "PARM ", DYN_LGNONE);
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\n", DYN_LGNONE);
@@ -2002,7 +2085,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
if(tok == r.listesep && tok2 == r.ident) ; else break;
n++;
dynField(e, valex, tmp, 1, norig(n), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
dynConcatSz(e, resultat, "PARM ", DYN_LGNONE);
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\n", DYN_LGNONE);
@@ -2024,6 +2107,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
/* -------------------------------------------------------------------------------------- */
if(tok == r.do_ || tok == r.call || tok == r.invoke)
{
//ent16 toksub = tok; // si besoin pour differencier do/call/invoke
dynSetLen(e, &envers, 0);
/* 3 formes : do var ; do ident@ident ; do library@ident
invoke ident&ident call ident */
@@ -2032,7 +2116,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynConcatSz(e, resultat, "\nCRAZ\n", DYN_LGNONE);
if(tok == r.call || tok == r.invoke)
{
/* appel de module ou de library **FINIR** */
/* appel de module ou de library */
if(tok == r.call)
{
tok2 = nreg(n+1);
@@ -2045,7 +2129,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
/* appel lib CLIB */
dynLet(e, &envers, "CLIB ", DYN_LGNONE);
dynField(e, valex, tmp, 1, norig(n + 1), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
if(encours->mLg > 255 || encours->mLg < 1)
{
dynField(e, valex, tmp, 3, norig(n + 1), cFM, cVM, 1);
@@ -2072,7 +2156,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
}
/* appel d'un module */
dynField(e, valex, tmp, 1, norig(n + 1), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
if(encours->mLg > 21 || encours->mLg < 1)
{
dynField(e, valex, tmp, 3, norig(n + 1), cFM, cVM, 1);
@@ -2082,7 +2166,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynLet(e, &envers, "MODL ", DYN_LGNONE);
dynConcat(e, &envers, encours);
dynField(e, valex, tmp, 1, norig(n + 3), cFM, cVM, 1);
dynIconv(e, tmp, encours, "X");
hex2str(e, tmp, encours);
if(encours->mLg > 23 || encours->mLg < 1)
{
dynField(e, valex, tmp, 3, norig(n + 3), cFM, cVM, 1);
@@ -2134,29 +2218,79 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
tok = nreg(n);
if(tok != r.endpar)
{
dynSetLen(e, &varparam, 0);
doVarParam = 1;
/* au moins 1 var en parametre */
for(;;)
{
dynSetLen(e, &trav, 0);
aGauche = 0;
derPvah = 0;
if(variable(e, &trav, valex, tmp, encours, &aGauche) == VAR_ERR)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : parametre do/call/invoke incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
dynConcatSz(e, &trav, "CPHA", DYN_LGNONE);
if(derPvah)
{
int np = dynDcount(e, &trav, '\n', DYN_NONE, DYN_NONE);
if(np >= 3)
dynInsSz(e, &trav, np - 1, DYN_NONE, "SADV", 4, '\n', DYN_NONE);
}
dynConcatSz(e, &trav, derPvah ? "CPHH" : "CPHA", DYN_LGNONE);
dynIns(e, &envers, 1, DYN_NONE, &trav, '\n', DYN_NONE);
if(tok == r.endpar)
break;
if(tok != r.listesep)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : parametre do/call/invoke incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
n++;
}
/* TODO => controler certaines formes de variables passees en parametre (varparam) :
(a, a) (a, a.b) (a.b, a.b.c) (a!c) : sont interdites
*/
if(doVarParam == 2)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : parametre do/call/invoke avec indirection non autorisee\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
doVarParam = 0;
long i, j, nbi, nbj, nb = dynDcount(e, &varparam, cFM, DYN_NONE, DYN_NONE);
for(i = 2; i < nb; i++)
for(j = i + 1; j <= nb; j++)
{
// comparer i et j
dynField(e, &varparam, tmp, i, DYN_NONE, cFM, DYN_NONE, 1);
dynField(e, &varparam, encours, j, DYN_NONE, cFM, DYN_NONE, 1);
if(dynCompare(e, tmp, CMP_EQ, encours->mPtr, encours->mLg))
{
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : parametres do/call/invoke identiques non autorises\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
nbi = dynDcount(e, tmp, cVM, DYN_NONE, DYN_NONE);
nbj = dynDcount(e, encours, cVM, DYN_NONE, DYN_NONE);
if(nbi == nbj)
continue;
if(nbi > nbj)
nbi = nbj; // nbi est le min de var enchainees : comparer sur le min, si egal : non autorise
dynField(e, &varparam, tmp, i, 1, cFM, cVM, nbi);
dynField(e, &varparam, encours, j, 1, cFM, cVM, nbi);
if(dynCompare(e, tmp, CMP_EQ, encours->mPtr, encours->mLg))
{
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : parametres do/call/invoke imbriques, de meme base, non autorises\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
}
}
if(nreg(n+1) != 0)
{
@@ -2178,8 +2312,11 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynConcatSz(e, resultat, "\n", DYN_LGNONE);
n++;
aGauche = 1;
dynSetLen(e, &varparam, 0);
doVarParam = 1; // pour ctrl new : "classe.membre = new classe" non autorise
if(variable(e, &envers, valex, tmp, encours, &aGauche) == VAR_ERR)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : variable let incorrecte\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
@@ -2187,6 +2324,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
setfld = 0; // 1 pour x{1} et 2 pour x{1,1}
if(tok == r.beginh)
{
doVarParam = 0;
if(expr(e, resultat, valex, tmp, encours, 0, r.let) != 0) // var{ is followed by 1 or 2 expr, comma separated
{
/* erreur dans l'expression */
@@ -2198,6 +2336,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
setsubstr = 0; // 1 pour x[1,1]
if(tok == r.begins)
{
doVarParam = 0;
if(expr(e, resultat, valex, tmp, encours, 0, r.change) != 0) // var[ is followed by 2 expr, comma separated
{
/* erreur dans l'expression */
@@ -2208,6 +2347,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
}
if(tok != r.equal)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : let incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
@@ -2216,6 +2356,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
tok = nreg(n);
if(tok == r.beginh)
{
doVarParam = 0;
if(setfld != 0 || setsubstr != 0)
{
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
@@ -2325,6 +2466,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
{
if(setfld != 0 || setsubstr != 0)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : creation objet incorrecte\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
@@ -2336,19 +2478,30 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
/* TODO : indirection sur le nom de la classe : var a la place de ident dans ce cas la */
if(tok == r.ident && tok2 == 0) ; else
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : new incorrect\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
dynField(e, valex, &envers, 1, norig(n), cFM, cVM, 1);
dynIconv(e, &envers, tmp, "X");
hex2str(e, &envers, tmp);
if(tmp->mLg < 1 || tmp->mLg > 24)
{
doVarParam = 0;
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : new, classe incorrecte\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
// pbm test suivant si new appele dans library...
doVarParam = 0;
/* si "tmp" (la classe) est le premier element de varparam : non autorise */
dynField(e, &varparam, &envers, 2, 1, cFM, cVM, 1);
if(dynCompare(e, &envers, CMP_EQ, tmp->mPtr, tmp->mLg))
{
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : new, classe non autorise quand mise a jour membre pour elle meme\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
// pbm test suivant si new appele dans library et classe declaree dans le prog principal (ou inversement)... donc plus de controle
if(IdentInconnu(e, tmp))
{
//dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
@@ -2358,7 +2511,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
}
if(aGauche == 2)
{
// TODO dercode avec une var a creer : PHDN/PIDN - TODO
// dercode avec une var a creer : PHDN/PIDN
dercode.mPtr[3] = 'N';
dynConcat(e, resultat, &dercode);
}
@@ -2369,6 +2522,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
else
{
/* expression "simple" */
doVarParam = 0;
if(expr(e, resultat, valex, tmp, encours, 0, 0) != 0)
{
/* erreur dans l'expression */
@@ -2436,7 +2590,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
dynConcat(e, resultat, &envers);
if(setfld == 0)
{
// TODO var[] DESV DESH DESI
// var[] DESV DESH DESI
if(aGauche != 2)
dynConcatSz(e, resultat, "DESV\n", 5); // une seule var a gauche DESV
else
@@ -2450,7 +2604,7 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
}
else
{
// TODO var{}[] DEZV DEZH DEZI
// var{}[] DEZV DEZH DEZI
if(aGauche != 2)
dynConcatSz(e, resultat, "DEZV\n", 5); // une seule var a gauche DEZV
else
@@ -2478,14 +2632,14 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
return DYN_ERR;
}
dynField(e, valex, &envers, 1, norig(n), cFM, cVM, 1); /* tmp est le nom de la nouvelle classe */
dynIconv(e, &envers, tmp, "X");
hex2str(e, &envers, tmp);
n++;
if(nreg(n) == r.equal && nreg(n+1) == r.beginh && nreg(n+2) == r.ident && nreg(n+3) == r.endh)
{
/* classe mere */
n += 2;
dynField(e, valex, &dercode, 1, norig(n), cFM, cVM, 1);
dynIconv(e, &dercode, &envers, "X"); /* envers est le nom de la classe mere */
hex2str(e, &dercode, &envers);
// verif classe mere connue
if(IdentInconnu(e, &envers))
{
@@ -2530,37 +2684,33 @@ long parse(env * e, Dynamic * valex, Dynamic * resultat, Dynamic * tmp, Dynamic
if(tok == r.echo) strcpy(instr, "WRIT\n"); else strcpy(instr, "WRLN\n");
/* */
n++;
tok = nreg(n);
tok2 = nreg(n+1);
/* temporaire pour tests, A FINIR */
if(tok == r.ident && tok2 == 0) // enlever tok2 == 0 FINIR
{
aGauche = 0;
if(variable(e, resultat, valex, tmp, encours, &aGauche) == VAR_ERR)
{
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : variable echo incorrecte\n", numlig, tmp->mPtr);
return DYN_ERR; /* TODO numeroter les erreurs */
}
dynConcatSz(e, resultat, instr, 5);
}
else if((tok == r.stringdq || tok == r.stringq) && tok2 == 0)
{
dynConcatSz(e, resultat, "PVAT\nDSET \"", DYN_LGNONE); /* TODO pbm " dans la chaine : quid ?? */
tok2string(e, valex, tmp, encours);
dynChange(e, encours, "\"", "#22", DYN_ALL);
dynChange(e, encours, " ", "#20", DYN_ALL);
dynConcat(e, resultat, encours);
dynConcatSz(e, resultat, "\"\n", DYN_LGNONE);
dynConcatSz(e, resultat, instr, 5);
}
else
/* expression "simple" */
doVarParam = 0;
if(expr(e, resultat, valex, tmp, encours, 0, 0) != 0)
{
/* erreur dans l'expression */
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : fin echo/echonl incorrect\n", numlig, tmp->mPtr);
printf("Erreur ligne %dc%s : expression let incorrecte\n", numlig, tmp->mPtr);
return DYN_ERR;
}
if(tok != 0)
{
/* erreur en fin d'expression */
dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
printf("Erreur ligne %dc%s : fin d'expression let incorrecte\n", numlig, tmp->mPtr);
return DYN_ERR;
}
dynConcatSz(e, resultat, instr, 5);
return OK;
/* */
//aGauche = 0;
//if(variable(e, resultat, valex, tmp, encours, &aGauche) == VAR_ERR)
//{
// dynField(e, valex, tmp, 3, norig(n), cFM, cVM, 1);
// printf("Erreur ligne %dc%s : variable echo incorrecte\n", numlig, tmp->mPtr);
// return DYN_ERR; /* TODO numeroter les erreurs */
//}
//dynConcatSz(e, resultat, instr, 5);
}
/* -------------------------------------------------------------------------------------- */
if(tok == r.delet)
+8
View File
@@ -76,6 +76,14 @@ WAPIDECL char * copy_nom(env * e, const char * s)
return e->nom;
}
WAPIDECL char * raz_nom(env * e)
{
e->nom64[0] = 0;
e->nom64[1] = 0;
e->nom64[2] = 0;
return e->nom;
}
WAPIDECL int modFnIs(env * e, const char * fn, int lg)
{
// modifier l'endroit ou e->fn est mis a jour : verif fn64[0 1 2] est bien remis a zero avant la maj
+1
View File
@@ -28,6 +28,7 @@
WAPIDECL void init_env(env * e);
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);
/* ************************************************************************** */
+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);
+29 -499
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,486 +54,7 @@ static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
}
static void encodageMD2(env * e, var * entree, var * sortie)
{
unsigned char checksum[16] = {0};
unsigned char padding[16] = {0};
unsigned char buffer[48] = {0};
ent64 i, j, k;
static unsigned char tpi[]={ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19, 98, 167, 5, 243, 192, 199, 115,
140, 152, 147, 43, 217, 188, 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138,
23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122, 169, 104, 121,
145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231,
191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207,
101, 230, 45, 168, 2, 27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 85, 71, 163, 35,
221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244,
65, 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74, 120, 136, 149, 139,
227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248,
235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
unsigned char * p = (unsigned char *)(entree->ptr);
unsigned char L = 0, T;
long longueur = entree->mLg;
while(longueur >= 16)
{
for(i = 0; i < 16; i++)
{
buffer[16 + i] = *p++;
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
longueur -= 16;
}
if(longueur > 0)
{
memcpy(padding, p, longueur);
}
ent64 nb = 16 - longueur;
memset(padding + longueur, nb, nb);
// calcul MD2 sur dernier bloc avec padding
for(i = 0; i < 16; i++)
{
buffer[16 + i] = padding[i];
checksum[i] = (L = checksum[i] ^ tpi[L ^ buffer[16 + i]]);
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
// calcul MD2 sur checksum
for(i = 0; i < 16; i++)
{
buffer[16 + i] = checksum[i];
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
T = 0;
for(j = 0; j < 18; j++)
{
for(k = 0; k < 48; k++)
buffer[k] = (T = buffer[k] ^ tpi[T]);
T = (T + j) & 255;
}
//
/* fin du calcul md2 : en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i = 0, j = 0; i < 16; i++)
{
sortie->ptr[j++] = carhex[buffer[i] / 16];
sortie->ptr[j++] = carhex[buffer[i] % 16];
}
dynSetLen(e, sortie, j); // len = 32 ici
}
static void majMD4(unsigned int * md4, pointeur buffer)
{
unsigned int A, B, C, D, tmp;
unsigned int buf[16];
unsigned char * octet;
ent64 i;
#define rot(T,s) (tmp = T, (tmp<<s) | (tmp>>(32-s)))
#define f(W,X,Y,Z,i,r) W = rot((W + ((X&Y) | ((~X)&Z)) + buf[i]),r)
#define g(W,X,Y,Z,i,r) W = rot(((W + ((X&Y) | (X&Z) | (Y&Z))) + buf[i] + 0x5A827999),r)
#define h(W,X,Y,Z,i,r) W = rot((W + (X^Y^Z) + buf[i] + 0x6ED9EBA1),r)
/* coder le buffer en little endian */
octet = buffer;
for(i=0; i<16; i++, octet+=4)
buf[i] = (*octet) | ((*(octet+1))<<8) | ((*(octet+2))<<16) | ((*(octet+3))<<24);
/* */
/* printf("%08x %08x\n",buffer[0], buf[0]); */
A = md4[0];
B = md4[1];
C = md4[2];
D = md4[3];
/* Round 1 */
f(A , B , C , D , 0 , 3);
f(D , A , B , C , 1 , 7);
f(C , D , A , B , 2 , 11);
f(B , C , D , A , 3 , 19);
f(A , B , C , D , 4 , 3);
f(D , A , B , C , 5 , 7);
f(C , D , A , B , 6 , 11);
f(B , C , D , A , 7 , 19);
f(A , B , C , D , 8 , 3);
f(D , A , B , C , 9 , 7);
f(C , D , A , B , 10 , 11);
f(B , C , D , A , 11 , 19);
f(A , B , C , D , 12 , 3);
f(D , A , B , C , 13 , 7);
f(C , D , A , B , 14 , 11);
f(B , C , D , A , 15 , 19);
/* Round 2 */
g(A , B , C , D , 0 , 3);
g(D , A , B , C , 4 , 5);
g(C , D , A , B , 8 , 9);
g(B , C , D , A , 12 , 13);
g(A , B , C , D , 1 , 3);
g(D , A , B , C , 5 , 5);
g(C , D , A , B , 9 , 9);
g(B , C , D , A , 13 , 13);
g(A , B , C , D , 2 , 3);
g(D , A , B , C , 6 , 5);
g(C , D , A , B , 10 , 9);
g(B , C , D , A , 14 , 13);
g(A , B , C , D , 3 , 3);
g(D , A , B , C , 7 , 5);
g(C , D , A , B , 11 , 9);
g(B , C , D , A , 15 , 13);
/* Round 3 */
h(A , B , C , D , 0 , 3);
h(D , A , B , C , 8 , 9);
h(C , D , A , B , 4 , 11);
h(B , C , D , A , 12 , 15);
h(A , B , C , D , 2 , 3);
h(D , A , B , C , 10 , 9);
h(C , D , A , B , 6 , 11);
h(B , C , D , A , 14 , 15);
h(A , B , C , D , 1 , 3);
h(D , A , B , C , 9 , 9);
h(C , D , A , B , 5 , 11);
h(B , C , D , A , 13 , 15);
h(A , B , C , D , 3 , 3);
h(D , A , B , C , 11 , 9);
h(C , D , A , B , 7 , 11);
h(B , C , D , A , 15 , 15);
/* */
md4[0] += A;
md4[1] += B;
md4[2] += C;
md4[3] += D;
}
static void encodageMD4(env * e, var * entree, var * sortie)
{
unsigned char lg[8];
unsigned char buffer[64];
unsigned int md4[4]; // forcer sur 32 bits
ent64 i, j, k;
static char carhex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
/* */
md4[0] = (unsigned int)0x67452301;
md4[1] = (unsigned int)0xefcdab89;
md4[2] = (unsigned int)0x98badcfe;
md4[3] = (unsigned int)0x10325476;
long longueur = entree->mLg;
*(ent64 *)lg = (ent64)longueur * 8;
/* */
pointeur p = entree->ptr;
while(longueur >= 64)
{
majMD4(md4, p);
p += 64;
longueur -= 64;
}
/* traitement du dernier bloc */
/* ajouter 0x80 et dans les 8 derniers octets le nombre de bits du flux initial (unsigned long long) */
/* si pas assez de place, faire un nouveau bloc */
memset(buffer, 0, 64);
if(longueur > 0)
memcpy(buffer, p, longueur);
buffer[longueur] = 128; /* 0x80 */
if(longueur <= 55)
{
/* un seul dernier bloc */
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, buffer);
}
else
{
/* 2 derniers blocs */
majMD4(md4, buffer);
/* */
memset(buffer, 0, 64);
// encoder la longueur en little endian
*(unsigned char *)(buffer+56) = *(ent64 *)lg & 255;
*(unsigned char *)(buffer+57) = (*(ent64 *)lg >> 8) & 255;
*(unsigned char *)(buffer+58) = (*(ent64 *)lg >> 16) & 255;
*(unsigned char *)(buffer+59) = (*(ent64 *)lg >> 24) & 255;
*(unsigned char *)(buffer+60) = (*(ent64 *)lg >> 32) & 255;
*(unsigned char *)(buffer+61) = (*(ent64 *)lg >> 40) & 255;
*(unsigned char *)(buffer+62) = (*(ent64 *)lg >> 48) & 255;
*(unsigned char *)(buffer+63) = (*(ent64 *)lg >> 56) & 255;
majMD4(md4, buffer);
}
//
/* calcul md4 en hexa dans sortie (tableau de 32 cars mini) et binaire dans binaire */
for(i=0, j=0, k=0; i<4; i++, j+=8, k+=4)
{
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j] = carhex[buffer[0]/16];
sortie->ptr[j+1] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j+2] = carhex[buffer[0]/16];
sortie->ptr[j+3] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
md4[i] >>= 8;
sortie->ptr[j+4] = carhex[buffer[0]/16];
sortie->ptr[j+5] = carhex[buffer[0]%16];
/* */
buffer[0] = md4[i] & 255;
sortie->ptr[j+6] = carhex[buffer[0]/16];
sortie->ptr[j+7] = carhex[buffer[0]%16];
}
dynSetLen(e, sortie, 32);
}
/* MD5 stuff, as of RFC 1321 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (ent32)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
static void encodageMD5(env * e, var * entree, var * sortie)
{
ent32 a, b, c, d, s0, s1, s2, s3, i, x[16];
unsigned char buffer[64];
/* */
s0 = 0x67452301;
s1 = 0xefcdab89;
s2 = 0x98badcfe;
s3 = 0x10325476;
/* */
long len64 = entree->mLg % 64;
long nb64 = entree->mLg / 64;
long der1 = 0, der2 = 0, der3 = 0;
if(len64 < 56)
{
// dernier bloc : len64(entree) 1(128) 55-len64(0) 8(mLg)
der1 = ++nb64;
}
else
{
// avant dernier bloc : len64(entree) 1(128) 63-len64(0)
// dernier bloc : 0(56) 8(mLg)
der2 = ++nb64;
der3 = ++nb64;
}
ent64 nb = (ent64)(entree->mLg * 8); /* en bits */
pointeur p = entree->ptr;
/* pour chaque bloc de 64 octets (512 bits) */
for(long cpt = 1; cpt <= nb64; cpt++)
{
if(cpt == der1)
{
// dernier bloc cas modulo < 56
memset(buffer, 0, 64);
if(len64 > 0)
memcpy(buffer, p, len64);
buffer[len64] = 128;
buffer[56] = (nb) & 0xff;
buffer[57] = (nb >> 8) & 0xff;
buffer[58] = (nb >> 16) & 0xff;
buffer[59] = (nb >> 24) & 0xff;
buffer[60] = (nb >> 32) & 0xff;
buffer[61] = (nb >> 40) & 0xff;
buffer[62] = (nb >> 48) & 0xff;
buffer[63] = (nb >> 56) & 0xff;
p = buffer;
}
else if(cpt == der2)
{
// avant dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
memcpy(buffer, p, len64);
buffer[len64] = 128;
p = buffer;
}
else if (cpt == der3)
{
// dernier bloc cas modulo >= 56
memset(buffer, 0, 64);
buffer[56] = (nb) & 0xff;
buffer[57] = (nb >> 8) & 0xff;
buffer[58] = (nb >> 16) & 0xff;
buffer[59] = (nb >> 24) & 0xff;
buffer[60] = (nb >> 32) & 0xff;
buffer[61] = (nb >> 40) & 0xff;
buffer[62] = (nb >> 48) & 0xff;
buffer[63] = (nb >> 56) & 0xff;
p = buffer;
}
/* deplier la boucle ? */
for (i = 0; i < 16; i++)
{
x[i] = ((ent32)(*p++));
x[i] |= (((ent32)(*p++)) << 8);
x[i] |= (((ent32)(*p++)) << 16);
x[i] |= (((ent32)(*p++)) << 24);
}
//hex(p, 64);
/* */
a = s0;
b = s1;
c = s2;
d = s3;
/* Round 1 */
FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x02441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[ 6], S34, 0x04881d05); /* 44 */
HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
/* */
s0 += a;
s1 += b;
s2 += c;
s3 += d;
}
p = sortie->ptr; /* 16 octets en hexa */
char hexa[16] = "0123456789abcdef";
/* */
*p++ = hexa[(s0 >> 4) & 0xf];
*p++ = hexa[(s0) & 0xf];
*p++ = hexa[(s0 >> 12) & 0xf];
*p++ = hexa[(s0 >> 8) & 0xf];
*p++ = hexa[(s0 >> 20) & 0xf];
*p++ = hexa[(s0 >> 16) & 0xf];
*p++ = hexa[(s0 >> 28) & 0xf];
*p++ = hexa[(s0 >> 24) & 0xf];
/* */
*p++ = hexa[(s1 >> 4) & 0xf];
*p++ = hexa[(s1) & 0xf];
*p++ = hexa[(s1 >> 12) & 0xf];
*p++ = hexa[(s1 >> 8) & 0xf];
*p++ = hexa[(s1 >> 20) & 0xf];
*p++ = hexa[(s1 >> 16) & 0xf];
*p++ = hexa[(s1 >> 28) & 0xf];
*p++ = hexa[(s1 >> 24) & 0xf];
/* */
*p++ = hexa[(s2 >> 4) & 0xf];
*p++ = hexa[(s2) & 0xf];
*p++ = hexa[(s2 >> 12) & 0xf];
*p++ = hexa[(s2 >> 8) & 0xf];
*p++ = hexa[(s2 >> 20) & 0xf];
*p++ = hexa[(s2 >> 16) & 0xf];
*p++ = hexa[(s2 >> 28) & 0xf];
*p++ = hexa[(s2 >> 24) & 0xf];
/* */
*p++ = hexa[(s3 >> 4) & 0xf];
*p++ = hexa[(s3) & 0xf];
*p++ = hexa[(s3 >> 12) & 0xf];
*p++ = hexa[(s3 >> 8) & 0xf];
*p++ = hexa[(s3 >> 20) & 0xf];
*p++ = hexa[(s3 >> 16) & 0xf];
*p++ = hexa[(s3 >> 28) & 0xf];
*p++ = hexa[(s3 >> 24) & 0xf];
/* */
dynSetLen(e, sortie, 32);
return err == OK ? OK : EX_MODERR;
}
/* *********************************************************************************** */
@@ -592,13 +115,16 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
if(param1 == NULL)
exc = EX_MODETAT;
// renvoie la version du module/plugins
else if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); // version 1 ici
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN;
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(modFnIs(e, "error", 5))
{
@@ -618,13 +144,10 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ============================================================================================= */
else if(modFnIs(e, "MD2", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
@@ -634,13 +157,10 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD4", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
@@ -650,13 +170,10 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "MD5", 3))
{
p_etat->error = 0;
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else if(param2->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
@@ -664,6 +181,19 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
}
}
/* ----------------------------------------------------------------------------------------------- */
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);
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
setError(p_etat, 0); // evite un warning de compil
+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);
}
+73 -4
View File
@@ -98,7 +98,13 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
if(varht == NULL || v == NULL || nom == NULL)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
{
if((varht = (var *)varht->ptr) == NULL) /* travailler avec la var pointee ! */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
/* chaque groupe : | nom1 ... 0 (24) | var1 (40) | nom2 ... 0 (24) | var2 (40) | */
@@ -129,6 +135,7 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
pentry->nom2 = 0;
pentry->nom3 = 0;
pentry->content.type = 0;
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return;
}
if(action == HASH_WRITE) /* write */
@@ -140,6 +147,7 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
var_let(e, &pentry->content, *v, TRUE, FALSE); /* verifier que TRUE et FALSE sont ok ici !!! */
}
((entry *)varht->ptr)->pvar = &pentry->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
}
return;
}
@@ -182,6 +190,7 @@ WAPIDECL void hashtable_do(env * e, int action, var * varht, char * nom, var **
pfree->content.type = VAR_NULL;
var_let(e, &pfree->content, *v, FALSE, FALSE); /* copie de la var */
((entry *)varht->ptr)->pvar = &pfree->content; /* adresse ou la var a ete ecrite */
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
//printf("hashwrite non trouve %s %p -> %p (ad e->int_dynamic %p)\n", nom, *v, &pfree->content, &e->int_dynamic);
}
}
@@ -211,6 +220,7 @@ WAPIDECL int hashtable_next(env * e, var * varht, char * nom, var ** v)
{
var * pvar;
entry * pentry;
if(((entry *)varht->ptr)->content.ptr == NULL) return FALSE; /* write/delete sur la hash durant le select : arret ! */
/* ne fait pas une copie de la variable en retour, mais renvoie un pointeur dans la hash !! */
for(pvar = &((entry *)varht->ptr)->content; pvar->type < varht->modulo; pvar->type++)
{
@@ -281,8 +291,8 @@ WAPIDECL void hashtable_clear(env * e, var * varht)
hashtable_free_ovf(e, varht);
/* raz contenu */
memset(varht->ptr, 0, varht->modulo * varht->separateur);
/* raz ptr par securite */
hashtable_select(e, varht);
/* raz ptr par securite (utile ??) */
//hashtable_select(e, varht);
}
WAPIDECL long hashtable_count(env *e, var * varht)
@@ -294,10 +304,67 @@ WAPIDECL long hashtable_count(env *e, var * varht)
while(hashtable_next(e, varht, e->nom, &pvar))
nb++;
/* raz ptr par securite */
hashtable_select(e, varht);
//hashtable_select(e, varht);
((entry *)varht->ptr)->content.ptr = NULL; /* securite si dans select/next */
return nb;
}
WAPIDECL void hashtable_serialize(env * e, var * varht, var * out)
{
/* >>> format (ignorer sub/null/buffer/param), point d'entree = hash
N:nom\n
number\n
D:lg:nom\n
dynamic\n (lg ne tient pas compte du \n)
+:nom\n
<contenu hash/objet>
-:\n (fin hash)
S:nom()\n (que le nom de la sub)
*/
if(varht == NULL || out == NULL) return;
if((varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT) || out->type != VAR_DYNAMIC) return;
/* */
var * v;
hashtable_select(e, varht);
while(hashtable_next(e, varht, raz_nom(e), &v))
{
if(v->type == VAR_NUMBER)
{
dynConcatSz(e, out, "N:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
dynConcatSz(e, out, NumberToSz(e, v->num, NULL, NULL), DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
}
else if (v->type == VAR_DYNAMIC)
{
dynConcatSz(e, out, "D:", 2);
dynConcatSz(e, out, Int64ToSz(e, v->mLg, FALSE, 0), DYN_LGNONE);
dynConcatSz(e, out, ":", 1);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
dynConcat(e, out, v);
dynConcatSz(e, out, "\n", 1);
}
else if (v->type == VAR_SUBROUTINE)
{
dynConcatSz(e, out, "S:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "()\n", 3);
}
else if(v->type == VAR_HASHTABLE || v->type == VAR_OBJECT)
{
dynConcatSz(e, out, "+:", 2);
dynConcatSz(e, out, e->nom, DYN_LGNONE);
dynConcatSz(e, out, "\n", 1);
/* */
hashtable_serialize(e, v, out);
/* */
dynConcatSz(e, out, "-:\n", 3);
}
}
}
WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
{
entry * pentry; /* pointe sur une entree */
@@ -311,6 +378,8 @@ WAPIDECL void hashtable_printdebug(env * e, var * varht, int detail)
return;
if(varht->type == VAR_PARAM)
varht = (var *)varht->ptr; /* travailler avec la var pointee ! */
if(varht == NULL)
return;
if(varht->type != VAR_HASHTABLE && varht->type != VAR_OBJECT)
return;
if(e->demon)
+2
View File
@@ -33,6 +33,8 @@ 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);
/* ********************************************** */
+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;
}
+17 -9
View File
@@ -41,14 +41,14 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"INTE" "FRAC" "NEGN" "ABSN" "MODL" "PSHC" "PSHV" "POPV" "PVAR" "PVAH"
"WRIT" "WRLN" "DSET" "DEXV" "DCMP" "DSTO" "LETV" "DCAT" "DTON" "NTOD"
"DELE" "HLET" "CLAS" "NLET" "INCL" "PNAM" "PSH0" "PSH1" "PSH2" "PSH3"
"PSH4" "PSH5" "PSH6" "PSH7" "PSH8" "PSH9" "PSHA" "PROG" "BACK" "CLIB"
"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" "SDBG" "PHDN" "PIDN" "SADV" "VLET" /* 110-119 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" /* 124 */
"PHDV" "PIDV" "HCOU" "PVHD" "PVID" "SSRC" "SSCS" "CPHH" "xxxx" "xxxx" /* 127 */
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
@@ -61,7 +61,7 @@ char libInstr[256 * 4] ={"VERS" "JUMP" "DECL" "SRCL" "BEXC" "EXCE" "CATC" "THRW"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx"
"xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" "xxxx" /* 200-249 */
"xxxx" "LIBR" "ENDL" "TEST" "ENDS" "ENDP"};
"PROG" "LIBR" "ENDL" "BACK" "ENDS" "ENDP"};
char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "FOR"};
@@ -184,10 +184,10 @@ char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "F
#define IN_PSH9 55
#define IS_PSHA "\x38"
#define IN_PSHA 56
#define IS_PROG "\x39"
#define IN_PROG 57
#define IS_BACK "\x3A"
#define IN_BACK 58
#define IS_SQRT "\x39"
#define IN_SQRT 57
#define IS_IEXP "\x3A"
#define IN_IEXP 58
#define IS_CLIB "\x3B"
#define IN_CLIB 59
@@ -326,13 +326,21 @@ char libComp[10 * 3] = {"EQ " "NE " "LT " "GT " "LE " "GE " "AND" "OR " "NOT" "F
#define IN_PVHD 123
#define IS_PVID "\x7C"
#define IN_PVID 124
#define IS_SSRC "\x7D"
#define IN_SSRC 125
#define IS_SSCS "\x7E"
#define IN_SSCS 126
#define IS_CPHH "\x7F"
#define IN_CPHH 127
#define IS_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"
+995 -308
View File
File diff suppressed because it is too large. Load diff
+33 -9
View File
@@ -87,16 +87,17 @@ enum {
VAR_OBJECT = 7, /* idem hashtable mais en objet : seule diff. element "_class" cree dans la table (interne) */
VAR_BUFFER = 8, /* usage interne : pile calcul + pile appel sub (autre ? buffer circulaire ptr read/write) */
VAR_NB = 8,
VAR_EMPTY = 0, /* retour @empty */
VAR_EMPTY = 0, /* retour @empty fonction type(expr) */
VAR_UNDECLARED = -1,
VAR_UNDECLARED = 0, /* cas de retour si pas de var dans "typeof var1.var2.var3" */
WCP_ASCII = 0, /* pour valeur par defaut */
WCP_WIN1252 = 1252,
WCP_8859_1 = 28591,
WCP_8859_15 = 28605,
WCP_UTF8 = 65001,
WCP_DEFAULT = WCP_WIN1252 // UTF8 ??
WCP_DEFAULT = WCP_ASCII // WIN1252 ? UTF8 ?
};
typedef struct {
@@ -133,7 +134,7 @@ typedef struct {
ent64 write; /* buffer */
ent64 misc; /* hashtable/objet et subroutine (si_except) */
ent64s mInternal; /* pour dynamic */
pointeur etat; /* pour module, etat utilise d'appels en appels */
pointeur etat; /* pour module (SUB), etat utilise d'appels en appels ; pour VAR_PARAM indique si variable est un element de hash (PVAH) */
};
} var; /* 40 octets */
@@ -253,7 +254,12 @@ enum {
EX_CHILD_FORK = 38, /* erreur de fork sur nouveau process */
EX_CHILD_EXEC = 39, /* erreur execution nouveau process */
EX_ZERO_FOR_INCR = 40, /* erreur increment a zero dans une boucle foreach numerique */
EXNB = 40 /* MEMO !!!! */
EX_SORTEDSEARCH_KO = 41, /* erreur de parametre (type de tri incorrect) */
EX_SQRT_NEG = 42, /* racine carre d'un nombre negatif non calculee */
EX_INT_EXP = 43, /* exponentiation fractionnaire non calculee */
EX_VARPARAM_KO = 44, /* la variable passee en parametre n'est plus presente en memoire */
EX_PARAM_NOTFOUND = 45, /* la variable passee en parametre est affectee a un nom de parametre inconnu de la sub */
EXNB = 45 /* MEMO !!!! */
};
typedef struct {
@@ -325,23 +331,27 @@ typedef struct {
pointeur si_except; /* position dans le source du code traitant les exceptions (apres instruction EXC) */
/* */
pointeur binaddr; /* permet de lire les adresses binaires en mode Trace */
/* */
pointeur ctxLzw; /* pointeur sur le contexte lzw pour decompresser les binaires wp compresse */
/* */
ent64 mem_numb; /* nombre de blocs memoire alloues */
ent64 mem_size; /* taille des bloc memoire alloues */
/* */
ent64 oid_cpt; /* compteur pour les object ID (OID) */
/* */
char oidc[24]; /* conversion en ascii, mis en binaire (16 chiffres max car 2x8 octets), oid3 ne sert pas (0)
seuls les 15 premiers cars servent, les 8 derniers sont des fillers pour aller a 24 cars */
char oidc[24]; /* conversion en ascii, mis en binaire (16 chiffres max car 2x8 octets), oid3 ne sert pas (0)
seuls les 15 premiers cars servent, les 8 derniers sont des fillers pour aller a 24 cars */
/* */
union { /* var interne pour copie d'une cle d'acces a un element d'une hashtable */
ent64 nom64[3];
char nom[24];
};
int zero1; /* permet de gerer la chaine precedente nom en sz */
union {
ent64 fn64[3];
char fn[24]; // nom de la fonction appelee par un module (max 23 cars)
char fn[24]; /* nom de la fonction appelee par un module (max 23 cars) - A REVOIR avec le int zero qui suit !! */
};
int zero2; /* permet de gerer la chaine precedente nom en sz */
/* */
/* table des caracteres de '000' a '999' (pour conversion) */
char tbl_1000[3000];
@@ -362,6 +372,20 @@ enum {
CMP_FOR = 10
};
enum {
FORMAT_TRIM = 1,
FORMAT_LEFT = 2,
FORMAT_RIGHT = 3,
FORMAT_CENTER = 4,
FORMAT_SURROUND = 5
};
enum {
SORTEDSEARCH_NONE = 0,
SORTEDSEARCH_ASC = 1, // = DYN_SORT_ASC
SORTEDSEARCH_DESC = 2 // = DYN_SORT_DESC
};
#define GUV_CLASS "_class"
#define GUV_BINADDR "_binaddr"
#define GUV_LOCAL "_local"
@@ -375,7 +399,7 @@ enum {
#define GUV_BIN "_bin"
#define GUV_WDIR "_wdir"
#define VARSYS "@varnull,@varnumber,@varsubroutine,@varparam,@vardynamic,@varhashtable,@varobject,@varbuffer,@false,@true,@level,@kill,@oid,@prog,@exceptstr,@exceptline,@except,@part,@line,@os,@vers,@verw,@demon,@endian,@file,@arg,@pi,@fm,@vm,@svm,@tm,@currfm,@currvm,@number,@dynamic,@empty,@trim,@left,@right,@center,@surround;1,2,3,4,5,6,7,8,10,11,12,13,14,15,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,40,41,42,50,51,52,53,54"
#define 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"
+331 -51
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,69 +47,254 @@ reste: (1,1,#00-#FF) ;11; 1,1,00-FF
[] est remplace par () car cela revient au meme !
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include "lex.h"
#include "convert.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
static 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)
{
// 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;
}
WAPIDECL void init_reg_lex(env * e, Dynamic * regles, Dynamic * tmp)
{
rlex.blanc = rg_lex(e, regles, "blanc", tmp); // 1
rlex.nomregle = rg_lex(e, regles, "nomregle", tmp); // 2
rlex.debut = rg_lex(e, regles, "debut", tmp); // 3
rlex.fin = rg_lex(e, regles, "fin", tmp); // 4
rlex.occ = rg_lex(e, regles, "occ", tmp); // 5
rlex.infini = rg_lex(e, regles, "infini", tmp); // 6
rlex.commentaire = rg_lex(e, regles, "commentaire", tmp); // 7
rlex.intervalle = rg_lex(e, regles, "intervalle", tmp); // 8
rlex.hexa = rg_lex(e, regles, "hexa", tmp); // 9
rlex.car = rg_lex(e, regles, "car", tmp); // 10
rlex.reste = rg_lex(e, regles, "reste", tmp); // 11
}
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"
long regles_lex(env * e, Dynamic * r)
WAPIDECL long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
dynLet(e, r, "", 0);
dynConcatSz(e, r, "blanc,1,nomregle,2,debut,3,fin,4,occ,5,infini,6,commentaire,7,intervalle,8,hexa,9,car,10,reste,11\n", DYN_LGNONE);
dynConcatSz(e, r, "1,-1,20:09\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,61-7A;0,-1,30-39:61-7A;1,1,3A\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,28\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,29\n", DYN_LGNONE);
dynConcatSz(e, r, "1,9,30-39;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2A;1,1,2C\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,3B;0,-1,09-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,2D\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,23;2,2,30-39:41-46\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,21-7E\n", DYN_LGNONE);
dynConcatSz(e, r, "1,1,00-FF", DYN_LGNONE);
return DYN_OK;
}
//
long lire_regles_lex(env * e, Dynamic * regles, char * fichier_lex)
{
long cr;
long cr = DYN_ERR;
if(fichier_lex != NULL)
{
/* selon fichier_lex, lire directement depuis le source */
if(strncmp(fichier_lex, "debuglex", 8) == 0)
{
if(*file_debuglex == 0)
#ifdef WINLIB
cr = dynRead(e, regles, "C:\\Users\\Poupougne42\\source\\repos\\win_w_src\\lex\\debuglex"); // lire les regles depuis le fichier sur disque
#else
cr = dynRead(e, regles, "/etc/wlanguage/debuglex"); // lire les regles depuis le fichier sur disque
#endif
else
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
cr = dynLet(e, regles, file_debuglex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "wlex", 4) == 0)
{
if(*file_wlex == 0)
#ifdef WINLIB
cr = dynRead(e, regles, "C:\\Users\\Poupougne42\\source\\repos\\win_w_src\\lex\\wlex"); // lire les regles depuis le fichier sur disque
#else
cr = dynRead(e, regles, "/etc/wlanguage/wlex"); // lire les regles depuis le fichier sur disque
#endif
else
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
cr = dynLet(e, regles, file_wlex, DYN_LGNONE);
}
else if(strncmp(fichier_lex, "lexlex", 6) == 0)
{
cr = dynLet(e, regles, file_lexlex, DYN_LGNONE);
}
else
cr = dynRead(e, regles, fichier_lex); // lire les regles depuis le fichier sur disque
}
else
cr = regles_lex(e, regles); // par defaut, charger les regles lex des fichiers "lex" (?!)
//
if(cr == DYN_OK)
{
dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
//dynDel(e, regles, 1, DYN_NONE, 10, DYN_NONE, 1); /* la premiere ligne contient le <numero,nom> des regles, separe par "," */
}
//dynErase(e, regles, "\r"); /* nettoyage au cas ou fichier Windows */
return cr;
}
//
long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
static long concorde_h(env * e, Dynamic * chaine, Dynamic * regle, Dynamic * elem, Dynamic * detail)
{
long conc = 1, lgconc = 0, fin = FALSE, ichaine = 0, nch, t1, t2, trouve;
long occmin, occmax, occtrouve, occsuiv;
@@ -208,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
@@ -361,6 +546,101 @@ void lex(env * e, Dynamic * regles, Dynamic * saisie, Dynamic * valex)
dynFree(e, &motencours);
dynFree(e, &trouvemot);
}
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 = ""
+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
+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;
}
+43 -5
View File
@@ -1,8 +1,46 @@
//static char file_debuglex[] = "";
// !! 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\n1,2,61-7A:41-5A\n1,1,3F\n1,9,30-39\n1,1,2B\n1,1,2D\n1,1,3A;1,1,61-7A:41-5A:5F;0,23,61-7A:41-5A:30-39\n1,1,2E;1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,00-FF";
"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";
//static char file_wlex[] = "";
static char file_wlex[] = "blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60,format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70,lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80,indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90,multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99\n"
"1,-1,20:09\n1,1,3B;0,-1,00-FF\n1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E\n1,1,62;1,1,61;1,1,63;1,1,6B;1,1,67;1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,6C;1,1,69;1,1,62;1,1,72;1,1,61;1,1,72;1,1,79\n1,1,65;1,1,6E;1,1,64\n1,1,65;1,1,78;1,1,63;1,1,65;1,1,70;1,1,74\n1,1,74;1,1,68;1,1,72;1,1,6F;1,1,77\n1,1,63;1,1,61;1,1,74;1,1,63;1,1,68\n1,1,69;1,1,6E;1,1,63;1,1,6C;1,1,75;1,1,64;1,1,65\n1,1,73;1,1,75;1,1,62\n1,1,65;1,1,6E;1,1,64;1,1,73;1,1,75;1,1,62\n1,1,69;1,1,66\n1,1,74;1,1,68;1,1,65;1,1,6E\n1,1,65;1,1,6C;1,1,73;1,1,65\n1,1,65;1,1,6C;1,1,73;1,1,65;1,1,69;1,1,66\n1,1,65;1,1,6E;1,1,64;1,1,69;1,1,66\n1,1,64;1,1,6F\n1,1,63;1,1,61;1,1,6C;1,1,6C\n1,1,69;1,1,6E;1,1,76;1,1,6F;1,1,6B;1,1,65\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E\n1,1,72;1,1,65;1,1,74;1,1,75;1,1,72;1,1,6E;1,1,6F;1,1,6E\n1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,65;1,1,6E;1,1,64;1,1,6C;1,1,6F;1,1,6F;1,1,70\n1,1,66;1,1,6F;1,1,72;1,1,65;1,1,61;1,1,63;1,1,68\n1,1,69;1,1,6E\n1,1,6C;1,1,69;1,1,6B;1,1,65\n1,1,65;1,1,6E;1,1,64;1,1,66;1,1,6F;1,1,72\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B\n1,1,62;1,1,72;1,1,65;1,1,61;1,1,6B;1,1,6F;1,1,6E\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65\n1,1,63;1,1,6F;1,1,6E;1,1,74;1,1,69;1,1,6E;1,1,75;1,1,65;1,1,6F;1,1,6E\n1,1,6E;1,1,6F;1,1,70\n1,1,70;1,1,61;1,1,72;1,1,74\n1,1,65;1,1,63;1,1,68;1,1,6F;1,1,6E;1,1,6C\n1,1,65;1,1,63;1,1,68;1,1,6F\n1,1,69;1,1,6E;1,1,70;1,1,75;1,1,74\n1,1,64;1,1,65;1,1,63;1,1,6C;1,1,61;1,1,72;1,1,65\n1,1,6C;1,1,65;1,1,74\n1,1,64;1,1,65;1,1,6C;1,1,65;1,1,74\n1,1,6E;1,1,65;1,1,77\n1,1,63;1,1,6C;1,1,61;1,1,73;1,1,73\n1,1,74;1,1,68;1,1,69;1,1,73\n1,1,70;1,1,61;1,1,72;1,1,65;1,1,6E;1,1,74\n1,1,68;1,1,6F;1,1,6C;1,1,64\n1,1,70;1,1,72;1,1,65;1,1,63;1,1,69;1,1,73;1,1,69;1,1,6F;1,1,6E\n1,1,73;1,1,65;1,1,74;1,1,73;1,1,65;1,1,70\n1,1,69;1,1,6E;1,1,74\n1,1,66;1,1,72;1,1,61;1,1,63\n1,1,61;1,1,62;1,1,73\n1,1,6E;1,1,65;1,1,67\n1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64\n1,1,74;1,1,79;1,1,70;1,1,65\n1,1,6C;1,1,65;1,1,6E\n1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,64;1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74\n1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64\n1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78\n1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68\n1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65\n1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74\n1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74\n1,1,72;1,1,65;1,1,6D;1,1,6F;1,1,76;1,1,65\n1,1,74;1,1,6F;1,1,6E;1,1,75;1,1,6D\n1,1,74;1,1,6F;1,1,73;1,1,74;1,1,72;1,1,69;1,1,6E;1,1,67\n1,1,3D\n1,1,23\n1,1,3E\n1,1,3C\n1,1,3E;1,1,3D\n1,1,3C;1,1,3D\n1,1,61;1,1,6E;1,1,64\n1,1,6F;1,1,72\n1,1,6E;1,1,6F;1,1,74\n1,1,28\n1,1,29\n1,1,7B\n1,1,7D\n1,1,5B\n1,1,5D\n1,1,21\n1,1,3F\n1,1,22;0,765,20-21:23-EF;1,1,22\n1,1,27;0,765,20-26:28-EF;1,1,27\n1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39\n1,1,40;1,-1,61-7A\n1,13,30-39;1,1,2E;0,5,30-39\n1,13,30-39\n1,1,2D\n1,1,2B\n1,1,2A\n1,1,2F\n1,1,5C\n1,1,25\n1,1,3A\n1,1,2C\n1,1,2E\n1,1,26\n1,1,00-FF";
// 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";
+3
View File
@@ -70,6 +70,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
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 */
+1
View File
@@ -86,4 +86,5 @@ WAPIDECL int setPdfGraph(env * e, modContextPdf * ctxPdf, char type, long x, lon
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);
+9 -6
View File
@@ -202,9 +202,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else if(param2 == NULL)
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_HASHTABLE || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
@@ -323,13 +321,18 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
exc = setError(p_etat, ! pdfLoadImageBmp(e, &p_etat->cp, param1));
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;
}
}
/* ============================================================================================= */
+264
View File
@@ -22,6 +22,8 @@
********************************************** */
#include "pdf.h"
#include <string.h>
// force exporting
#ifdef WINLIB
#undef WAPIDECL
@@ -169,6 +171,69 @@ enum {
};
/* valeur en dixieme de mm * CONV11 / CONV2 = valeur en unites pdf x 100 (72 dpi = 72 points par pouce ; 1 pouce = 25.4) */
// dynOconv ne sert pas ailleurs : a voir a mettre dans conv.h ? autre ? (revoir mod Horodate)
#include "time.h"
static long dynOconv(env * e, Dynamic * this, Dynamic * resultat, char * format)
{
/* a revoir pour UTF8 ? (Base64 ?) oui pour D car d'autres cars utf8 peuvent etre dans la chaine */
char tmp[5];
//
switch(*format++)
{
case 'D': // obsolete ? utiliser le mod Horodate
{
struct tm * ptm;
/* conversion date/heure : format interne = time_t unix sur 32 bits */
time_t tm;
if(this->mLg == 0)
{
tm = time(NULL);
ptm = gmtime(&tm);
}
else
{
tm = dynToNum(e, this, DYN_NONE, 10); /* pas de signe, lg max sur 32 bits = 10 chiffres */
if(this->mInternal == DYN_ERR)
return DYN_ERR; /* pbm de conversion numerique */
ptm = localtime(&tm);
}
/* analyse formatage demande */
dynLet(e, resultat, NULL, DYN_LGNONE);
tmp[1] = 0;
while((tmp[0] = *format++))
switch(tmp[0])
{
case 'Y':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_year + 1900, DYN_NONE, 4), 4);
break;
case 'y':
dynConcatSz(e, resultat, Int32ToSz((ptm->tm_year + 1900) % 100, DYN_NONE, 2), 2);
break;
case 'M':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mon + 1, DYN_NONE, 2), 2);
break;
case 'D':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_mday, DYN_NONE, 2), 2);
break;
case 'h':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_hour, DYN_NONE, 2), 2);
break;
case 'm':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_min, DYN_NONE, 2), 2);
break;
case 's':
dynConcatSz(e, resultat, Int32ToSz(ptm->tm_sec, DYN_NONE, 2), 2);
break;
default:
dynConcatSz(e, resultat, tmp, 1);
break;
}
break;
}
}
return DYN_OK;
}
/* PRIVATE *****************************************************/
static int pdfEchap(env * e, Dynamic * resultat, Dynamic * chaine)
{
@@ -688,6 +753,205 @@ WAPIDECL int pdfLoadImageBmp(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
return TRUE;
}
WAPIDECL int pdfLoadImageGif(env * e, modContextPdf * ctxPdf, Dynamic * fichier)
{
/* https://www.fileformat.info/format/gif/egff.htm */
long larg, haut, offset, ind;
long gctEntry, gct;
long lctEntry, lct, interlace;
octet * p; /* pour simplifier le code... */
/* lecture fichier */
if(!fichier)
{
return FALSE;
}
if(fichier->type != VAR_DYNAMIC)
return FALSE;
/* controle du GIF avant memorisation */
p = fichier->ptr;
if(fichier->mLg < 13)
{
return FALSE;
}
if(strncmp((char *)p, "GIF87a", 6) != 0 && strncmp((char *)p, "GIF89a", 6) != 0)
{
return FALSE; /* pas un fichier GIF */
}
if(p[fichier->mLg - 1] != '\x3B')
return FALSE; /* pas un fichier GIF */
/* les entiers sont en little-endian */
larg = (p[7] << 8) + p[6];
haut = (p[9] << 8) + p[8];
//backColor = p[11];
gct = ((p[10] & 0x80) != 0); /* presence d'une global color table */
//gctSort = ((p[10] & 0x08) != 0); /* tri de la global color table */
gctEntry = 1 << ((p[10] & 0x07) + 1); /* taille de la global color table (max 256 entrees, chacune en RGB, donc x3) */
//gctColResolution = ((p[10] & 0x70) >> 4) + 1; /* nombre de bits par couleur (max 8) */
offset = 13;
if(gct)
{
gct = offset; /* offset de la gct dans le fichier */
offset += gctEntry * 3;
}
while(offset < fichier->mLg && p[offset] == '\x21')
{
/* extension, GIF89a only */
offset++;
if(offset < fichier->mLg && p[offset] == 0xF9) /* ATTENTION : un car est signé => '\xF9' est négatif !!! */
{
/* graphics control extension */
if(fichier->mLg < offset + 7)
return FALSE;
offset += 7;
}
else if(offset < fichier->mLg && p[offset] == 0xFE) /* ATTENTION : un car est signé => '\xFE' est négatif !!! */
{
/* comment extension */
if(fichier->mLg < offset + 2)
return FALSE;
/* "sauter" tous les blocks de commentaire */
offset++;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else if(offset < fichier->mLg && p[offset] == 0xFF) /* ATTENTION : un car est signé => '\xFF' est négatif !!! */
{
/* application extension */
if(fichier->mLg < offset + 13)
return FALSE;
/* "sauter" tous les blocks data */
offset += 13;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else if(offset < fichier->mLg && p[offset] == '\x01')
{
/* plaintext extension */
if(fichier->mLg < offset + 14)
return FALSE;
/* "sauter" tous les blocks data */
offset += 14;
while(offset + p[offset] + 1 < fichier->mLg && p[offset])
offset += p[offset] + 1;
offset += 2;
}
else
return FALSE; /* unknown extension : erreur */
}
/* ici, offset pointe sur la premier Local Image Descriptor */
if(fichier->mLg < offset + 10)
return FALSE; /* pas de partie image dans le fichier */
if(p[offset] != '\x2C')
return FALSE; /* pas de Local Image Descriptor */
/* */
larg = (p[offset + 6] << 8) + p[offset + 5];
haut = (p[offset + 8] << 8) + p[offset + 7];
lct = ((p[offset + 9] & 0x01) != 0); /* presence d'une local color table */
//lctSort = ((p[offset + 9] & 0x04) != 0); /* tri de la local color table */
interlace = ((p[offset + 9] & 0x02) != 0); /* interlace */
lctEntry = 1 << (((p[offset + 9] & 0xE0) >> 5) + 1); /* taille de la local color table (max 256 entrees, chacune en RGB, donc x3) */
offset += 10;
if(lct)
{
lct = offset; /* offset de la lct dans le fichier */
offset += lctEntry * 3;
}
/* decodage lzw de l'image a faire */
Dynamic gif, img, entre; /* gif = image decodee RGB, img = lzw decode, entre = gestion lignes entrelacees */
dynInit(e, &img, 4096);
/* mettre le decode dans img */
modContextLzw ctxLzw;
initLzw(e, &ctxLzw);
ctxLzw.inverse = TRUE; // lzw gif specifique
long type = 0; /* type = 1 : premier appel, 2 : appel suivant, 3 : dernier appel, 0 : un seul appel */
/* */
offset++; /* sauter le premier octet = lzw min code size */
while(offset < fichier->mLg && p[offset])
{
if(offset + p[offset] + 1 >= fichier->mLg)
printf("Erreur block lzw data gif\n"); /* TODO erreur de format : block plus grand que le reste du fichier */
if(p[offset + p[offset] + 1])
type = (type == 0) ? 1 : 2; /* pas le dernier bloc */
else
type = (type == 0 ? 0 : 3); /* dernier bloc */
/* */
memcopie(img.ptr, p + offset + 1, p[offset]);
img.mLg = p[offset];
/* */
getLzw(e, &img, &ctxLzw, type);
/* */
offset += p[offset] + 1;
}
/* TODO gerer erreurs (lg ko, lzw ko) */
freeLzw(e, &ctxLzw);
/* les lignes de l'image sont dans l'ordre de haut en bas, de gauche a droite
un octet par pixel donnant l'index soit dans la lct soit la gct de la couleur du pixel
si mode entrelace : les lignes sont dans l'ordre 0, +8, 4, +8, 2, +4, 1, +2
*/
//printf("avant image: larg %ld, haut %ld, offset %ld, val %d, gct %ld lct %ld\n", larg, haut, offset, p[offset], gct, lct);
//printf("img clair lg %lld, interlace:%ld\n", img.mLg, interlace);
long dx, dy, colind;
octet * q = img.ptr, * g, * h;
/* la bitmap en hexa fera une taille de larg*haut*3*2 */
dynInit(e, &gif, larg * haut * 3 * 2 + 1);
if(interlace)
{
dynInit(e, &entre, haut * 2 + 1);
short * ligent = (short *)entre.ptr, lig;
for(lig = 0; lig < (short)haut; lig += 8)
*ligent++ = lig;
for(lig = 4; lig < (short)haut; lig += 8)
*ligent++ = lig;
for(lig = 2; lig < (short)haut; lig += 4)
*ligent++ = lig;
for(lig = 1; lig < (short)haut; lig += 2)
*ligent++ = lig;
}
/* */
ind = dynDcount(e, &ctxPdf->mImg, cFM, DYN_NONE, DYN_NONE) + 1;
dynStoreNumber(e, &ctxPdf->mImg, ind, 1, larg, cFM, cVM);
dynStoreNumber(e, &ctxPdf->mImg, ind, 2, haut, cFM, cVM);
dynConcatSz(e, &ctxPdf->mImg, sVM, 1);
// boucle sur chaque pixel
g = gif.ptr;
for(dy = 0; dy < haut; dy++)
{
if(interlace)
{
/* gerer l'entrelacement */
g = gif.ptr + ((short *)entre.ptr)[dy] * larg * 3 * 2;
}
/* */
for(dx = 0; dx < larg; dx++)
{
colind = (lct ? lct : gct) + (*q++) * 3;
/* */
h = (octet *)dynConvertCharToCharHexa(p[colind++]);
*g++ = *h++;
*g++ = *h++;
h = (octet *)dynConvertCharToCharHexa(p[colind++]);
*g++ = *h++;
*g++ = *h++;
h = (octet *)dynConvertCharToCharHexa(p[colind]);
*g++ = *h;
*g++ = *h;
}
}
dynSetLen(e, &gif, larg * haut * 3 * 2);
dynConcat(e, &ctxPdf->mImg, &gif);
dynFree(e, &gif);
if(interlace)
dynFree(e, &entre);
dynFree(e, &img);
/* verifs si d'autres images ? */
/* eventuellement a la fin, decoder les blocks possibles (GIF89a only) : comment extension, plaintext extension : remettre le bloc "while" ci dessus des extensions
enfin, verifier le dernier octet du fichier : doit etre '\x3B' (GIF terminator)
*/
return TRUE;
}
WAPIDECL int pdfList(env * e, modContextPdf * ctxPdf, Dynamic * titre, Dynamic * lignes, long format)
{
// enchaine automatiquement les fonctions pour creer un pdf de type "listing" (log ou programme)
+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;
}
+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;
}
+15 -8
View File
@@ -110,19 +110,26 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
}
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
if(param1 == NULL)
exc = EX_MODPARAM;
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
else if(modFnIs(e, "error", 5))
{
// renvoie la derniere erreur specifique au module
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM;
else
{
if(param1->type == VAR_NUMBER)
@@ -134,7 +141,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ============================================================================================= */
else if(modFnIs(e, "get", 3))
{
if(!param1)
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
@@ -148,7 +155,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ============================================================================================= */
else if(modFnIs(e, "set", 3))
{
if(!param1 || !param2)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
+30 -17
View File
@@ -25,54 +25,67 @@
#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 LPWSAPOLLFD wPoll;
typedef Socket * wPoll;
#endif
/* codes a passer a la fonction setError */
enum {
EXMOD_SOCKET_ERROR = -1,
EXMOD_SOCKET_OK = 0,
EXMOD_SOCKET_INIT = 1,
SOCKET_LISTEN_MAX = 10
WSOCKET_END_CONNECT = -3,
WSOCKET_MEM_ERROR = -2,
WSOCKET_ERROR = -1,
WSOCKET_OK = 0,
WSOCKET_LISTEN_MAX = 10
};
typedef struct {
var * listSocket; // contient le tableau de pollfd/WSAPOLLFD encapsule dans un dynamic
Dynamic listSocket; // contient le tableau de pollfd/Socket encapsule dans un dynamic
int nbSocket; // nombre d'elements dans le tableau de pollfd
wPoll poll; // pointeur vers le tableau de pollfd/WSAPOLLFD
#ifdef UNIX
sigset_t mOldBlockSig,mBlockSig; /* gestion des signaux sur socket serveur en ecoute (utile ?) */
int posAddSocket; // endroit ou l'ajout a ete fait dans listSocket
wPoll poll; // pointeur vers le tableau de pollfd/Socket
Socket servSock;
Socket sock; // socket en cours (tmp)
int packet; // taille des paquets lus un par un
int err; // derniere erreur socket (errno ou WSAGetLastError())
#ifdef WINLIB
fd_set fds;
struct timeval tv;
#endif
} modContextSocket;
WAPIDECL void initSock(env * e, modContextSocket * ctx);
WAPIDECL void freeSock(env * e, modContextSocket * ctx);
WAPIDECL Socket NewSocket();
WAPIDECL int SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port);
WAPIDECL Socket AcceptClientSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL int SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * server);
WAPIDECL int AddSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL 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 int WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL int WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs);
WAPIDECL long WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL long WaitSocketForWrite(env * e, modContextSocket * ctx, int timeoutMs);
WAPIDECL long WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs);
WAPIDECL long WaitOneSocketForWrite(env * e, modContextSocket * ctx, Socket sock, int timeoutMs);
WAPIDECL void FreeSocket(env * e, modContextSocket * ctx, Socket sock);
WAPIDECL int GetSocketError();
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data);
WAPIDECL int SocketWouldBlock();
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data, long timeoutMs);
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data);
+154 -317
View File
@@ -41,22 +41,28 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "sock.h"
typedef struct {
int error; /* dernier code erreur specifique au module */
//***
modContextSocket cs;
// TODO a enlever quand sock_lib.c ok
int mSocket,mServeur;
#ifdef UNIX
sigset_t mOldBlockSig,mBlockSig; /* gestion des signaux sur socket serveur en ecoute */
#endif
modContextSocket ctxSock;
} modEtat;
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)
{
if(p != NULL)
@@ -71,7 +77,6 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
@@ -105,7 +110,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
p_etat = (modEtat *)(*etat);
p_etat->error = 0;
//***
initSock(e, &p_etat->cs);
initSock(e, &p_etat->ctxSock);
}
}
else if(modFnIs(e, "end", 3))
@@ -114,7 +119,7 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
freeSock(e, &p_etat->cs);
freeSock(e, &p_etat->ctxSock);
//***
memfree(e, p_etat);
}
@@ -122,22 +127,35 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
else if(modFnIs(e, "vers", 4))
{
// renvoie la version du module/plugins
if(param1->type == VAR_DYNAMIC)
dynLet(e, param1, "1", 1); //*** version en alpha
else if(param1->type == VAR_NUMBER)
param1->num = NUM_UN; //*** version en numerique
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(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->ctxSock.err);
}
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
@@ -147,369 +165,188 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* cree un point d'entree serveur */
if(p_etat == NULL)
{
exc = EX_MODETAT;
return exc;
}
// param<1> = numero de port ; TODO : mettre une VAR_NUMBER ??
long port = dynToNum(e, param1, 0, 5);
if(param1->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
}
if(port < 1024 || port > 65535)
{
exc = setError(p_etat, 1);
return exc;
}
//
struct sockaddr_in addr;
struct linger l_s; /* Structure pour setsockopt */
int sockopt, buf = 64000; /* taille buffer send/rec = 64 ko environ */
int arg = 1; /* pour ioctl */
// cree une socket serveur prete a ecouter
/* mise en place de la socket serveur d'ecoute */
if((p_etat->mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */
#endif
/* */
#ifdef UNIX
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
#endif
/* */
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
// linger n'impacte QUE le close de la socket, a voir si vraiment utile avec shutdown...
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
if(bind(p_etat->mSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
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(modFnIs(e, "connect", 7))
{
char ** tParam;
/* connexion a un serveur */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(dynDcount(e, param1, cFM, DYN_NONE, DYN_NONE) < 2)
exc = EX_MODPARAM; /* erreur */
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, param1, cFM);
if(tParam == NULL)
exc = EX_MODPARAM; /* erreur */
}
if(exc != OK)
return exc;
long port = atoi(tParam[1]);
if(param1->mInternal == DYN_ERR)
{
exc = setError(p_etat, 1);
return exc;
}
if(port < 1 || port > 65535)
{
exc = setError(p_etat, 1);
return exc;
}
//
struct hostent * serv;
struct sockaddr_in addr;
struct linger l_s; /* Structure pour setsockopt */
int sockopt, buf = 64000; /* taille buffer send/rec = 64 ko environ */
int arg = 1; /* pour ioctl */
// cree une socket serveur prete a ecouter
/* mise en place de la socket serveur d'ecoute */
if((p_etat->mSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
#ifdef UNIX
ioctl(p_etat->mSocket, FIONBIO, &arg); /* socket non bloquant (sys/ioctl.h) */
#endif
/* */
#ifdef UNIX
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int))) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
#endif
/* */
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_RCVBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_SNDBUF, (void*)&buf, sizeof(buf)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
// linger n'impacte QUE le close de la socket, a voir si vraiment utile avec shutdown...
l_s.l_onoff = 1;
l_s.l_linger = 0; // les 2 valeurs provoquent un close avec retour immediat, sans traiter les donnees eventuelles en attente d'envoi et envoi RST au client s'il est connecte en TCP
if(setsockopt(p_etat->mSocket, SOL_SOCKET, SO_LINGER, (void*)&l_s, sizeof (l_s)))
{
close(p_etat->mSocket); /* erreur */
exc = setError(p_etat, 1);
p_etat->mSocket = 0;
return exc;
}
/* */
/* pour l'adresse, soit host soit ip */
if((serv = gethostbyname(tParam[0])) == NULL)
; /* erreur */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(serv->h_addr);
if (connect(p_etat->mSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
; /* erreur : lire errno : EISCONN (deja:ok), EINPROGRESS EALREADY (en cours:ressayer), sinon erreur */
else
{
p_etat->mServeur = 2; /* client */
#ifdef UNIX
sigemptyset(&p_etat->mOldBlockSig);
sigfillset(&p_etat->mBlockSig);
#endif
// 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(modFnIs(e, "arret", 5))
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); // 2 = RDWR sous Unix, shutdown permet de se passer de SO_LINGER !?
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(modFnIs(e, "attente", 7))
else if(modFnIs(e, "stop", 4))
{
/* arret connexion cliente */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
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(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)
{
fd_set masque;
struct timeval delai;
long cr;
// attend une activite sur la socket, timeOut en 1/10 de sec.
delai.tv_sec = param1->num / NUM_FACTEUR; // x sec
delai.tv_usec = (param1->num % NUM_FACTEUR) * 10; // y µsec
FD_ZERO(&masque);
FD_SET(p_etat->mSocket, &masque);
//
if(p_etat->mServeur == 0)
{
// pour que le select() fonctionne a chaque fois (a chaque time-out), il faut remettre à jour
// les variables "delai" et "masque fd" ; il faut aussi imperativement
// bloquer les signaux !! la socket peut etre bloquante (mais il vaut mieux la mettre non bloquante)
#ifdef UNIX
sigprocmask(SIG_SETMASK, &p_etat->mBlockSig, &p_etat->mOldBlockSig);
#endif
cr = select(p_etat->mSocket + 1, &masque, NULL, NULL, &delai);
#ifdef UNIX
sigprocmask(SIG_SETMASK, &p_etat->mOldBlockSig, NULL);
#endif
}
// 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)
param1->num = NUM_UN; /* ok pour lire */
else
param1->num = NUM_ZERO; /* pas de donnees */
// si cr > 0 : ok pour continuer et lire la socket
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "get", 3))
{
long nblu = 0, arg = 1, flagInProgress = 0, pas = 16000, would_block;
/* lecture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
else if(param1 == NULL || param2 == NULL || param3 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->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, param1, 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, param1, param1->mLg + pas, 1)) /* avec recopie */
{
exc = setError(p_etat, 1);
break;
}
would_block = 0;
while((nblu = read(p_etat->mSocket, param1->mPtr + param1->mLg, pas)) < 0 && errno == EWOULDBLOCK /* WouldBlock = 11 */
&& (param1->mLg == 0 || flagInProgress) && (++would_block) < 100)
#ifdef UNIX
usleep(10000); /* attente de 10 ms entre chaque appel, maxi 100 fois (a garder ?) */
#else
Sleep(10);
#endif
if(errno == EINPROGRESS) /* 115 */
flagInProgress = 1; /* indique un envoi en plusieurs parties : ne plus sortir quand getLen # 0 car lecture pas finie ! */
if(nblu > 0)
dynSetLen(e, param1, param1->mLg + nblu);
/* */
} while (nblu > 0);
/* 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(modFnIs(e, "set", 3))
{
long nb , pos = 0, lg, would_block;
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_DYNAMIC)
else if(param1->type != VAR_NUMBER || param2->type != VAR_DYNAMIC)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
lg = param1->mLg;
while(lg > 0)
{
would_block = 0;
while((nb = write(p_etat->mSocket, param1->mPtr + pos, lg)) < 0 && errno == EWOULDBLOCK
&& (++would_block) < 100)
#ifdef UNIX
usleep(10000); /* attente 10 ms entre chaque appel, maxi 100 fois (a garder ?) */
#else
Sleep(10);
#endif
if(nb <= 0)
{
exc = setError(p_etat, 2);
break;
}
lg -= nb;
if(lg > 0)
pos += nb; /* ecriture en plusieurs fois */
}
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "accept", 6))
{
/* ecriture sur la connexion */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL)
exc = EX_MODPARAM; /* erreur */
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM; /* erreur */
if(exc == OK)
{
struct sockaddr_in addr_cnx;
unsigned int size_addr_cnx = sizeof(addr_cnx);
int sock;
if((sock = accept(p_etat->mSocket, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
param1->num = sock * NUM_FACTEUR; /* nouvelle requete entrante : renvoie num socket */
else
param1->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;
+344 -113
View File
@@ -25,6 +25,8 @@
#include "dynamic.h"
#include <errno.h>
#include <fcntl.h>
#ifdef WINLIB
#include <ws2tcpip.h>
#endif
@@ -45,7 +47,12 @@
/* ****** PUBLIC ************************ */
WAPIDECL void initSock(env * e, modContextSocket * ctx)
{
dynSetLen(e, ctx->listSocket, 0); // raz liste sockets
dynInit(e, &ctx->listSocket, DYN_LGMIN);
dynSetLen(e, &ctx->listSocket, 0); // raz liste sockets
ctx->servSock = INVALID_SOCKET;
ctx->sock = INVALID_SOCKET;
ctx->packet = 16000;
ctx->nbSocket = 0;
//
#ifdef WINLIB
WSADATA wsa;
@@ -55,13 +62,25 @@ WAPIDECL void initSock(env * e, modContextSocket * ctx)
WAPIDECL void freeSock(env * e, modContextSocket * ctx)
{
// TODO fermer les sockets ouvertes
/* 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()
WAPIDECL Socket NewSocket(env * e, modContextSocket * ctx)
{
#ifdef WINLIB
BOOL bOptVal = TRUE;
@@ -70,7 +89,7 @@ WAPIDECL Socket NewSocket()
int iOptLen = sizeof(int);
u_long block_mode = 1; // 1 = non-bloquant, 0 = bloquant
#else
int sockopt = 1;
int sockopt = 1; // 1 = non-bloquant, 0 = bloquant
#endif
struct linger l_s; /* Structure pour setsockopt */
Socket sock;
@@ -80,14 +99,13 @@ WAPIDECL Socket NewSocket()
#else
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
#endif
return EXMOD_SOCKET_ERROR;
{
ctx->err = GetSocketError();
return WSOCKET_ERROR;
}
/* */
#ifndef WINLIB
ioctl(sock, FIONBIO, &sockopt); /* socket non bloquant (sys/ioctl.h) */
// autre maniere
//int flags = fcntl(fd, F_GETFL, 0);
//if (flags == -1) return -1;
//if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) return -1;
#else
ioctlsocket(sock, FIONBIO, &block_mode);
#endif
@@ -99,30 +117,61 @@ WAPIDECL Socket NewSocket()
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&bOptVal, bOptLen)) /* pour eliminer une erreur : permet de rouvrir des socket suite a fermeture avec des clients encore connectes */
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
return WSOCKET_ERROR;
}
/* 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 EXMOD_SOCKET_ERROR;
return WSOCKET_ERROR;
}
/* autres options ? */
return sock;
/* 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 int SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port)
WAPIDECL long SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int port)
{
struct sockaddr_in addr;
//
@@ -133,48 +182,65 @@ WAPIDECL int SocketSetServer(env * e, modContextSocket * ctx, Socket sock, int p
#ifndef WINLIB
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
#else
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == EXMOD_SOCKET_ERROR)
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
return WSOCKET_ERROR;
}
#ifndef WINLIB
if(listen(sock, SOCKET_LISTEN_MAX) < 0)
if(listen(sock, WSOCKET_LISTEN_MAX) < 0)
#else
if(listen(sock, SOCKET_LISTEN_MAX) == EXMOD_SOCKET_ERROR)
if(listen(sock, WSOCKET_LISTEN_MAX) == SOCKET_ERROR)
#endif
{
ctx->err = GetSocketError();
#ifndef WINLIB
close(sock);
#else
closesocket(sock);
#endif
return EXMOD_SOCKET_ERROR;
return WSOCKET_ERROR;
}
return EXMOD_SOCKET_OK;
if(AddSocket(e, ctx, sock) == WSOCKET_OK)
{
ctx->servSock = sock;
return WSOCKET_OK;
}
else
return WSOCKET_ERROR;
}
WAPIDECL Socket AcceptClientSocket(env * e, modContextSocket * ctx, Socket sock)
WAPIDECL long AcceptClientSocket(env * e, modContextSocket * ctx)
{
struct sockaddr_in addr_cnx;
unsigned int size_addr_cnx = sizeof(addr_cnx);
Socket clientSock;
ctx->sock = 0;
#ifndef WINLIB
if((clientSock = accept(sock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
unsigned int size_addr_cnx = sizeof(addr_cnx);
if((ctx->sock = accept(ctx->servSock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) >= 0)
#else
if((clientSock = accept(sock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) != INVALID_SOCKET)
int size_addr_cnx = sizeof(addr_cnx);
if((ctx->sock = accept(ctx->servSock, (struct sockaddr *)&addr_cnx, &size_addr_cnx)) != INVALID_SOCKET)
#endif
return clientSock;
{
if(AddSocket(e, ctx, ctx->sock) == WSOCKET_OK)
return WSOCKET_OK;
else
return WSOCKET_ERROR;
}
else
return EXMOD_SOCKET_ERROR;
{
ctx->err = GetSocketError();
return WSOCKET_ERROR;
}
}
WAPIDECL int SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * server)
WAPIDECL long SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock, int port, var * server)
{
struct sockaddr_in addr;
struct hostent * serv;
@@ -185,96 +251,233 @@ WAPIDECL int SocketConnectToServer(env * e, modContextSocket * ctx, Socket sock,
#ifndef WINLIB
if(inet_aton(server->mPtr, &(addr.sin_addr)) == 0)
#else
if(InetPton(AF_INET, server->mPtr, &addr) == 1)
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 EXMOD_SOCKET_ERROR;
return WSOCKET_ERROR;
}
addr.sin_addr.s_addr = ((struct in_addr *)(serv->h_addr))->s_addr;
//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);
}
#ifndef WINLIB
if(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
/* 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(connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == EXMOD_SOCKET_ERROR)
if (ret < 0 && errno != EINPROGRESS)
{
ctx->err = GetSocketError();
close(sock);
return WSOCKET_ERROR;
}
#endif
if(AddSocket(e, ctx, sock) != WSOCKET_OK)
{
#ifndef WINLIB
close(sock);
#ifdef WINLIB
closesocket(sock);
#else
closesocket(sock);
close(sock);
#endif
return EXMOD_SOCKET_ERROR; /* erreur (TODO plusieurs essais avant erreur ?) */
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;
}
if(AddSocket(e, ctx, sock))
return EXMOD_SOCKET_OK;
else
return EXMOD_SOCKET_ERROR;
return WSOCKET_OK;
}
WAPIDECL int AddSocket(env * e, modContextSocket * ctx, Socket sock)
WAPIDECL long AddSocket(env * e, modContextSocket * ctx, Socket sock)
{
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket->ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
return TRUE; // deja present : RAF
// ajouter
if(! dynCtrl(e, ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return FALSE; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket->ptr;
ctx->poll[ctx->nbSocket].fd = sock;
ctx->poll[ctx->nbSocket++].events = POLLIN; // post incrementation car tableau base 0
return TRUE;
#ifndef WINLIB
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
{
ctx->posAddSocket = cpt;
return WSOCKET_OK; // deja present : RAF
}
// ajouter
if(dynCtrl(e, &ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return WSOCKET_MEM_ERROR; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket.ptr;
ctx->posAddSocket = ctx->nbSocket++; // post incrementation car tableau base 0
ctx->poll[ctx->posAddSocket].fd = sock;
ctx->poll[ctx->posAddSocket].events = POLLIN;
return WSOCKET_OK;
#else
// controle pas deja existant
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
{
ctx->posAddSocket = cpt;
return WSOCKET_OK; // deja present : RAF
}
// ajouter
if(dynCtrl(e, &ctx->listSocket, (ctx->nbSocket + 1) * sizeof(*ctx->poll), TRUE))
return WSOCKET_MEM_ERROR; // pbm memoire
ctx->poll = (wPoll)ctx->listSocket.ptr;
ctx->posAddSocket = ctx->nbSocket++; // post incrementation car tableau base 0
ctx->poll[ctx->posAddSocket] = sock;
return WSOCKET_OK;
#endif
}
WAPIDECL void DelSocket(env * e, modContextSocket * ctx, Socket sock)
{
ctx->poll = (wPoll)ctx->listSocket->ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
if(cpt < --ctx->nbSocket) // autre solution : mettre le fd en negatif : sera ignore par poll
ctx->poll[cpt] = ctx->poll[ctx->nbSocket]; // remplacer par le dernier (bouche le trou tout de suite)
}
WAPIDECL int WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs)
{
ctx->poll = (wPoll)ctx->listSocket->ptr;
#ifdef WINLIB
return WSAPoll(ctx->poll, ctx->nbSocket, timeoutMs);
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
if(cpt < --ctx->nbSocket) // autre solution : mettre le fd en negatif : sera ignore par poll
ctx->poll[cpt] = ctx->poll[ctx->nbSocket]; // remplacer par le dernier (bouche le trou tout de suite)
#else
return poll(ctx->poll, ctx->nbSocket, timeoutMs);
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt] == sock)
if(cpt < --ctx->nbSocket) // autre solution : mettre le fd en negatif : sera ignore par poll
ctx->poll[cpt] = ctx->poll[ctx->nbSocket]; // remplacer par le dernier (bouche le trou tout de suite)
#endif
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
}
WAPIDECL int WaitOneSocketForRead(env * e, modContextSocket * ctx, Socket sock, int timeoutMs)
WAPIDECL long WaitSocketForRead(env * e, modContextSocket * ctx, int timeoutMs)
{
ctx->poll = (wPoll)ctx->listSocket->ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
if(ctx->poll[cpt].fd == sock)
#ifdef WINLIB
return WSAPoll(&ctx->poll[cpt], 1, timeoutMs);
#else
return poll(&ctx->poll[cpt], 1, timeoutMs);
#endif
// socket pret a la lecture si (ctx->poll[cpt].revents & POLLIN) != 0 et poll retourne > 0, 0 = timeout (RAS), < 0 erreur (errno ou WSAGetLastError())
return EXMOD_SOCKET_ERROR;
#ifndef WINLIB
ctx->poll = (wPoll)ctx->listSocket.ptr;
for(int cpt = 0; cpt < ctx->nbSocket; cpt++)
ctx->poll[cpt].events = POLLIN;
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)
{
shutdown(sock, 2);
#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);
@@ -289,14 +492,23 @@ WAPIDECL int GetSocketError()
#endif
}
// TODO *********************************************************
// https://broux.developpez.com/articles/c/sockets
// https://learn.microsoft.com/fr-fr/windows/win32/winsock/using-winsock
// lecture / ecriture : utiliser send/recv => read/write fait idem avec attribute = 0
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data)
WAPIDECL int SocketWouldBlock()
{
int packetLg = 10000; // parametre ?
int timeoutMs = 100; // parametre ?
int err = GetSocketError();
#ifdef WINLIB
return (err == WSAEWOULDBLOCK || err == WSAEINTR);
#else
return (err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
#endif
}
// https://broux.developpez.com/articles/c/sockets
// https://learn.microsoft.com/fr-fr/windows/win32/winsock/using-winsock
// lecture / ecriture : utiliser send/recv => read/write fait idem avec attribute = 0
WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * data, long timeoutMs)
{
int packetLg = ctx->packet;
int nbTot = 0;
// code ici avec une socket non bloquante (sinon a revoir) ; ajouter dans la boucle le poll sur la socket quand besoin de reessayer
for(;;)
@@ -305,56 +517,75 @@ WAPIDECL long ReadSocket(env * e, modContextSocket * ctx, Socket sock, var * dat
int cr = WaitOneSocketForRead(e, ctx, sock, timeoutMs);
if(cr < 0)
{
if(errno == EINTR)
continue; // reprendre si signal
return -1; /* erreur */
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
if(cr == 0)
return nbTot; /* timeout : renvoi des donnees eventuellement deja lues */
return WSOCKET_OK; /* timeout : renvoi des donnees eventuellement deja lues */
/* */
if( ! dynCtrl(e, data, data->mLg + packetLg, TRUE))
if(dynCtrl(e, data, data->mLg + packetLg, TRUE))
{
return -2; // erreur memoire
return WSOCKET_MEM_ERROR; // erreur memoire
}
int nbRead = read(sock, data->mPtr + data->mLg, packetLg);
#ifdef WINLIB
int nbRead = recv(sock, data->mPtr + data->mLg, packetLg, 0);
#else
int nbRead = recv(sock, data->mPtr + data->mLg, packetLg, 0);
#endif
if(nbRead < 0)
{
if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
continue; // reprendre si signal
return -1; /* erreur */
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
if(nbRead == 0)
return -1; /* fin de lecture car fin du client */
if(nbRead == 0 && nbTot == 0)
return WSOCKET_END_CONNECT; /* fin de lecture car fin de la comm - A REVOIR */
/* nbRead positif ici */
data->mLg += nbRead;
dynSetLen(e, data, data->mLg + nbRead);
nbTot += nbRead;
if(nbRead < packetLg)
return WSOCKET_OK;
}
}
WAPIDECL long WriteSocket(env * e, modContextSocket * ctx, Socket sock, var * data)
{
//int timeoutMs = 100; // parametre ?
long len = data->mLg, nbTot = 0;
long len = data->mLg, nbTot = 0, timeoutMs = 1000;
if(len == 0)
return 0;
return WSOCKET_OK;
/* */
for(;;)
{
int nbWrite = write(sock, data->mPtr + nbTot, len);
if(nbWrite == 0)
return -1; /* fin du client */
// 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(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
{
// TODO : avant continuer, faire un poll sur la socket en ecriture idem read
continue; // reprendre si signal
}
return -1; /* erreur */
if(SocketWouldBlock())
continue;
ctx->err = GetSocketError();
return WSOCKET_ERROR; /* erreur */
}
len -= nbWrite;
nbTot += nbWrite;
if(len <= 0)
return nbTot; /* OK */
return WSOCKET_OK;
}
}
+85
View File
@@ -0,0 +1,85 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
#include "sqlite3.h"
typedef struct {
sqlite3 * sl3Handle;
sqlite3_stmt * sl3Request, * sl3Begin, * sl3Commit, * sl3Rollback, * sl3Cursor;
Dynamic confTable, stmt;
Dynamic request, pkfilter, colPk, colPkType, colAll, colAllType, error;
long nbStmt;
} modCtxSl3;
enum {
SL3ERR_PREPARE = 1,
SL3ERR_BIND = 2,
SL3ERR_NOPK = 3,
SL3ERR_NOTABLEINFO = 4,
SL3ERR_PREPARERW = 5,
SL3ERR_NORECORD = 6,
SL3ERR_COLTYPE = 7,
SL3ERR_READLOCK = 8,
SL3ERR_STEP = 9,
SL3ERR_WRITELOCK = 10,
SL3ERR_CREATE = 11,
SL3ERR_OPEN = 12,
SL3ERR_MEM = 13,
SL3ERR_TABLENOTPREP = 14,
SL3ERR_FETCH = -1
};
WAPIDECL void initSl3(env * e, modCtxSl3 * ctx);
WAPIDECL void freeSl3(env * e, modCtxSl3 * ctx);
WAPIDECL char * getErrorSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long openSl3(env * e, modCtxSl3 * ctx, const char * base);
WAPIDECL long createSl3(env * e, modCtxSl3 * ctx, const char * base);
WAPIDECL void closeSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long beginSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long commitSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long rollbackSl3(env * e, modCtxSl3 * ctx);
WAPIDECL long prepare_rwSl3(env * e, modCtxSl3 * ctx, char * table);
WAPIDECL void remove_rwSl3(env * e, modCtxSl3 * ctx, char * table);
WAPIDECL long getDescSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * desc);
WAPIDECL long readSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * key, Dynamic * record);
WAPIDECL long writeSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * record);
WAPIDECL long cursorSl3(env * e, modCtxSl3 * ctx, Dynamic * request, Dynamic * param);
WAPIDECL long fetchSl3(env * e, modCtxSl3 * ctx, Dynamic * record, long count);
WAPIDECL long createTableSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * colName, Dynamic * colType, long nbPk);
WAPIDECL long removeTableSl3(env * e, modCtxSl3 * ctx, char * table);
/*
1 base = 1 fichier sur disque (rm pour supprimer la base...), open ouvre ou cree la base (il suffit de verifier si le fichier existe...). Encodage = UTF-8
pas d'asynchrone (creer des threads/process) ; PRAGMA table_info(<table>) donne les infos sur une table (colonnes, types, PK etc.) ; pas de notion de schema (tout est dans la meme "base")
syntaxe pour binding dans requetes : ?1 ?2 ou :param1 $param2 @param3
docs : https://sqlite.org/capi3ref.html
sqlite3.c: The SQLite amalgamation source file
sqlite3.h: The header file that accompanies sqlite3.c and defines the C-language interfaces to SQLite.
shell.c: The command-line interface program itself.
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -lm -o sqlite3
gcc -fPIC -shared sqlite3.c -o libsqlite3.so -lpthread -ldl -lm
*/
+268826
View File
File diff suppressed because it is too large. Load diff
+14335
View File
File diff suppressed because it is too large. Load diff
+507
View File
@@ -0,0 +1,507 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sqlite.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
#define SQLITE_TYPE_TEXT "TEXT"
#define SQLITE_TYPE_INTEGER "INTEGER"
WAPIDECL void initSl3(env * e, modCtxSl3 * ctx)
{
dynInit(e, &ctx->stmt, DYN_LGMIN);
dynInit(e, &ctx->confTable, DYN_LGMIN);
dynInit(e, &ctx->request, DYN_LGMIN);
dynInit(e, &ctx->pkfilter, DYN_LGMIN);
dynInit(e, &ctx->colPk, DYN_LGMIN);
dynInit(e, &ctx->colPkType, DYN_LGMIN);
dynInit(e, &ctx->colAll, DYN_LGMIN);
dynInit(e, &ctx->colAllType, DYN_LGMIN);
dynInit(e, &ctx->error, DYN_LGMIN);
ctx->nbStmt = 0;
}
WAPIDECL void freeSl3(env * e, modCtxSl3 * ctx)
{
dynFree(e, &ctx->stmt);
dynFree(e, &ctx->confTable);
dynFree(e, &ctx->request);
dynFree(e, &ctx->pkfilter);
dynFree(e, &ctx->colPk);
dynFree(e, &ctx->colPkType);
dynFree(e, &ctx->colAll);
dynFree(e, &ctx->colAllType);
dynFree(e, &ctx->error);
}
WAPIDECL char * getErrorSl3(env * e, modCtxSl3 * ctx)
{
dynLet(e, &ctx->error, (char *)sqlite3_errmsg(ctx->sl3Handle), DYN_LGNONE);
return ctx->error.mPtr;
}
WAPIDECL long openSl3(env * e, modCtxSl3 * ctx, const char * base)
{
if(sqlite3_open_v2(base, &ctx->sl3Handle, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK)
return SL3ERR_OPEN;
else
{
dynSetLen(e, &ctx->stmt, 0);
ctx->nbStmt = 0;
dynSetLen(e, &ctx->confTable, 0);
// preparation des requetes de transaction
if(sqlite3_prepare_v2(ctx->sl3Handle, "BEGIN TRANSACTION", -1, &ctx->sl3Begin, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
if(sqlite3_prepare_v2(ctx->sl3Handle, "COMMIT TRANSACTION", -1, &ctx->sl3Commit, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
if(sqlite3_prepare_v2(ctx->sl3Handle, "ROLLBACK TRANSACTION", -1, &ctx->sl3Rollback, NULL) != SQLITE_OK)
return SL3ERR_PREPARE;
return OK; // connexion a une base ; pour la creer si elle n'existe pas : " | SQLITE_OPEN_CREATE "
}
}
WAPIDECL long createSl3(env * e, modCtxSl3 * ctx, const char * base)
{
if(sqlite3_open_v2(base, &ctx->sl3Handle, SQLITE_OPEN_CREATE, NULL) != SQLITE_OK)
return SL3ERR_CREATE;
sqlite3_close(ctx->sl3Handle);
return openSl3(e, ctx, base);
}
WAPIDECL void closeSl3(env * e, modCtxSl3 * ctx)
{
/* finalize stmt */
sqlite3_stmt ** p = (sqlite3_stmt **)ctx->stmt.ptr;
long cpt;
for(cpt = 0; cpt < ctx->nbStmt * 2; cpt++)
sqlite3_finalize(p[cpt]);
/* */
sqlite3_finalize(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Cursor);
sqlite3_finalize(ctx->sl3Begin);
sqlite3_finalize(ctx->sl3Commit);
sqlite3_finalize(ctx->sl3Rollback);
/* */
sqlite3_close(ctx->sl3Handle);
}
WAPIDECL long beginSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Begin);
if(sqlite3_step(ctx->sl3Begin) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long commitSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Commit);
if(sqlite3_step(ctx->sl3Commit) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long rollbackSl3(env * e, modCtxSl3 * ctx)
{
sqlite3_reset(ctx->sl3Rollback);
if(sqlite3_step(ctx->sl3Rollback) != SQLITE_DONE)
return SL3ERR_STEP;
else
return OK;
}
WAPIDECL long prepare_rwSl3(env * e, modCtxSl3 * ctx, char * table)
{
/*
confTable<1,x> = nom table
confTable<2,x> = nom colonne de la PK, dans l'ordre, separees par ","
confTable<3,x> = type de la colonne de la PK, lie avec confTable<2,x>
confTable<4,x> = nom de toutes les colonnes de la table, dans l'ordre, separees par ","
confTable<5,x> = type de toutes les colonnes de la table, dans l'ordre, lie avec confTable<4,x>
stmt[(x-1)*2] et stmt[(x-1)*2+1] = read/write stmt
*/
sqlite3_stmt * sl3read, * sl3write;
/* */
sqlite3_finalize(ctx->sl3Request);
dynLet(e, &ctx->request, "PRAGMA table_info(?1);", 22);
/* cid;name;type;notnull;dfltvalue;pk
0;kcust;INTEGER;0;;1
1;kind;INTEGER;0;;2
2;ident;TEXT;0;;0 */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
if(sqlite3_bind_text(ctx->sl3Request, 1, table, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
/* */
long nb = 0, cpt = 0;
/* read */
dynSetLen(e, &ctx->pkfilter, 0);
dynSetLen(e, &ctx->colPk, 0);
dynSetLen(e, &ctx->colPkType, 0);
dynSetLen(e, &ctx->colAll, 0);
dynSetLen(e, &ctx->colAllType, 0);
dynLet(e, &ctx->request, "select * from ", 14);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " where ", DYN_LGNONE);
/* */
while(sqlite3_step(ctx->sl3Request) == SQLITE_ROW) // peut renvoyer == SQLITE_DONE si pas de ligne, ou == SQLITE_ROW pour chaque ligne, ou == SQLITE_ERROR en cas d'erreur
{
/* les numeros des colonnes sont en base 0 */
if(strcmp((const char *)sqlite3_column_text(ctx->sl3Request, 2), SQLITE_TYPE_TEXT) != 0) return SL3ERR_COLTYPE;
if(strcmp((const char *)sqlite3_column_text(ctx->sl3Request, 2), SQLITE_TYPE_INTEGER) != 0) return SL3ERR_COLTYPE;
/* */
nb++;
dynStoreSz(e, &ctx->colAll, sqlite3_column_int64(ctx->sl3Request, 0) + 1, DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE, ',', DYN_NONE);
dynStoreSz(e, &ctx->colAllType, sqlite3_column_int64(ctx->sl3Request, 0) + 1, DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 2), DYN_LGNONE, ',', DYN_NONE);
if(sqlite3_column_int64(ctx->sl3Request, 5) > 0) // si c'est une colonne de la PK
{
if(++cpt > 1)
dynConcatSz(e, &ctx->pkfilter, " and ", DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, " = ?", DYN_LGNONE);
dynConcatSz(e, &ctx->pkfilter, Int32ToSz(cpt, FALSE, 0), DYN_LGNONE);
/* */
dynStoreSz(e, &ctx->colPk, sqlite3_column_int64(ctx->sl3Request, 5), DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 1), DYN_LGNONE, ',', DYN_NONE);
dynStoreSz(e, &ctx->colPkType, sqlite3_column_int64(ctx->sl3Request, 5), DYN_NONE, (char *)sqlite3_column_text(ctx->sl3Request, 2), DYN_LGNONE, ',', DYN_NONE); // TEXT INTEGER
}
}
sqlite3_finalize(ctx->sl3Request);
// si reset avant finalize, on peut reutiliser la requete preparee (repartir des bind), sinon il faut la preparer a nouveau ; reset => bind => step
if(cpt > 0)
{
dynConcat(e, &ctx->request, &ctx->pkfilter);
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &sl3read, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
}
else
return SL3ERR_NOPK;
/* */
dynLet(e, &ctx->request, "REPLACE INTO ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, (char *)table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " (", DYN_LGNONE);
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, ") VALUES (", DYN_LGNONE);
for(long i = 1; i <= nb; i++)
{
dynConcatSz(e, &ctx->request, i > 1 ? ",?" : "?", DYN_LGNONE);
dynConcatSz(e, &ctx->request, Int32ToSz(i, FALSE, 0), DYN_LGNONE);
}
dynConcatSz(e, &ctx->request, ") where ", DYN_LGNONE);
dynConcat(e, &ctx->request, &ctx->pkfilter);
if(nb > 0)
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &sl3write, NULL) != SQLITE_OK)
{
sqlite3_finalize(sl3write);
return SL3ERR_PREPARE;
}
/* memo dans ctx */
if(nb > 0)
{
if(dynCtrl(e, &ctx->stmt, (ctx->nbStmt + 1) * 2 * sizeof(pointeur), TRUE))
{
sqlite3_finalize(sl3read);
sqlite3_finalize(sl3write);
return SL3ERR_MEM;
}
sqlite3_stmt ** p = (sqlite3_stmt **)ctx->stmt.ptr;
p[ctx->nbStmt * 2] = sl3read;
p[ctx->nbStmt * 2 + 1] = sl3write;
ctx->nbStmt++;
long pos = dynDcount(e, &ctx->confTable, cVM, 1, cFM) + 1;
dynStoreSz(e, &ctx->confTable, 1, pos, (char *)table, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 2, pos, ctx->colPk.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 3, pos, ctx->colPkType.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 4, pos, ctx->colAll.mPtr, DYN_LGNONE, cFM, cVM);
dynStoreSz(e, &ctx->confTable, 5, pos, ctx->colAllType.mPtr, DYN_LGNONE, cFM, cVM);
/* */
return OK;
}
else
return SL3ERR_NOTABLEINFO;
}
WAPIDECL void remove_rwSl3(env * e, modCtxSl3 * ctx, char * table)
{
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return;
sqlite3_stmt * stmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2]; // read
sqlite3_finalize(stmt);
stmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2 + 1]; // write
sqlite3_finalize(stmt);
dynStoreSz(e, &ctx->confTable, 1, posTable, "@", 1, cFM, cVM);
/* remplacer celle supprimee par la derniere dans confTable et stmt ?? */
}
WAPIDECL long getDescSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * desc)
{
/* renvoie la liste des colonnes/cles de la table si "preparee" */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_TABLENOTPREP;
/* */
dynSetLen(e, desc, 0);
dynField(e, &ctx->confTable, &ctx->request, 4, posTable, cFM, cVM, 1); // colonnes
dynStore(e, desc, 1, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 5, posTable, cFM, cVM, 1); // type
dynStore(e, desc, 2, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 2, posTable, cFM, cVM, 1); // colonnes PK
dynStore(e, desc, 3, DYN_NONE, &ctx->request, cFM, DYN_NONE);
dynField(e, &ctx->confTable, &ctx->request, 3, posTable, cFM, cVM, 1); // colonnes PK type
dynStore(e, desc, 4, DYN_NONE, &ctx->request, cFM, DYN_NONE);
return OK;
}
WAPIDECL long readSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * key, Dynamic * record)
{
/* !! champs de key et record en VM !! */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
{
if(prepare_rwSl3(e, ctx, table) != OK)
return SL3ERR_PREPARERW;
posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_PREPARERW;
}
/* table prepare_rw ok ici, faire les bind sur la cle (au moins 1 colonne) */
sqlite3_stmt * readStmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2];
sqlite3_reset(readStmt);
/* */
dynField(e, &ctx->confTable, &ctx->colPkType, 3, posTable, cFM, cVM, 1); // type des colonnes de la PK
long pk, nbPk = dynDcount(e, &ctx->colPkType, ',', DYN_NONE, DYN_NONE);
if(nbPk == 0) return SL3ERR_NOPK;
for(pk = 1; pk <= nbPk; pk++)
{
dynField(e, &ctx->colPkType, &ctx->request, pk, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne de la PK
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, key, &ctx->request, pk, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_text(readStmt, 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, key, &ctx->request, pk, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_int64(readStmt, 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
int cr = sqlite3_step(readStmt);
if(cr == SQLITE_ROW)
{
dynSetLen(e, record, 0);
dynField(e, &ctx->confTable, &ctx->colAllType, 5, posTable, cFM, cVM, 1); // type des colonnes
long col, nbCol = dynDcount(e, &ctx->colAllType, ',', DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, &ctx->colAllType, &ctx->request, col, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
dynStoreSz(e, record, col, DYN_NONE, (char *)sqlite3_column_text(readStmt, col - 1), DYN_LGNONE, cVM, DYN_NONE);
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
dynStoreNumber(e, record, col, DYN_NONE, sqlite3_column_int64(readStmt, col - 1), cVM, DYN_NONE);
else
return SL3ERR_COLTYPE;
}
return OK;
}
else if(cr == SQLITE_DONE)
return SL3ERR_NORECORD;
else if(cr == SQLITE_BUSY)
return SL3ERR_READLOCK;
else
return SL3ERR_STEP;
}
WAPIDECL long writeSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * record)
{
/* !! champs de record en VM !! */
long posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
{
if(prepare_rwSl3(e, ctx, table) != OK)
return SL3ERR_PREPARERW;
posTable = dynLocateSz(e, &ctx->confTable, table, cVM, 1, cFM);
if(posTable == DYN_NOTFOUND)
return SL3ERR_PREPARERW;
}
/* table prepare_rw ok ici, faire les bind sur la cle (au moins 1 colonne) */
sqlite3_stmt * writeStmt = ((sqlite3_stmt **)ctx->stmt.ptr)[(posTable - 1) * 2 + 1];
sqlite3_reset(writeStmt);
/* */
dynField(e, &ctx->confTable, &ctx->colAllType, 5, posTable, cFM, cVM, 1); // type des colonnes
long col, nbCol = dynDcount(e, &ctx->colAllType, ',', DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, &ctx->colAllType, &ctx->request, col, DYN_NONE, ',', DYN_NONE, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, record, &ctx->request, col, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_text(writeStmt, 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, record, &ctx->request, col, DYN_NONE, cVM, DYN_NONE, 1);
if(sqlite3_bind_int64(writeStmt, 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
int cr = sqlite3_step(writeStmt);
if(cr == SQLITE_DONE)
return OK;
else if(cr == SQLITE_BUSY)
return SL3ERR_WRITELOCK;
else
return SL3ERR_STEP;
}
WAPIDECL long cursorSl3(env * e, modCtxSl3 * ctx, Dynamic * request, Dynamic * param)
{
/* param<1> = valeur champ (separateur VM) ; param<2> = type champ TEXT/INTEGER (separateur VM) */
sqlite3_finalize(ctx->sl3Cursor);
if(sqlite3_prepare_v2(ctx->sl3Handle, request->mPtr, -1, &ctx->sl3Cursor, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
/* binding */
dynField(e, param, &ctx->colAll, 1, DYN_NONE, cFM, DYN_NONE, 1);
dynField(e, param, &ctx->colAllType, 2, DYN_NONE, cFM, DYN_NONE, 1);
long col, nbCol = dynDcount(e, &ctx->colAllType, cVM, DYN_NONE, DYN_NONE);
for(col = 1; col <= nbCol; col++)
{
dynField(e, param, &ctx->request, 2, col, cFM, cVM, 1); // type de la colonne
if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_TEXT, DYN_LGNONE))
{
dynField(e, param, &ctx->request, 1, col, cFM, cVM, 1); // valeur
if(sqlite3_bind_text(ctx->sl3Cursor, col - 1, ctx->request.mPtr, -1, SQLITE_TRANSIENT) != SQLITE_OK) return SL3ERR_BIND;
}
else if(dynCompare(e, &ctx->request, CMP_EQ, SQLITE_TYPE_INTEGER, DYN_LGNONE))
{
dynField(e, param, &ctx->request, 1, col, cFM, cVM, 1); // valeur
if(sqlite3_bind_int64(ctx->sl3Cursor, col - 1, dynToNumber(e, &ctx->request)) != SQLITE_OK) return SL3ERR_BIND;
}
else
return SL3ERR_COLTYPE;
}
return OK;
}
WAPIDECL long fetchSl3(env * e, modCtxSl3 * ctx, Dynamic * record, long count)
{
/* count = 0 => tout lire en une seule fois ; renvoi le nombre d'enregs lus ; SL3ERR_FETCH si erreur */
dynSetLen(e, record, 0);
long nb = 0, cols, cpt;
int cr;
while((cr = sqlite3_step(ctx->sl3Cursor)) == SQLITE_ROW && (count == 0 || nb < count))
{
nb++;
/* remplir le record avec les donnees de la ligne */
cols = sqlite3_column_count(ctx->sl3Cursor); // si besoin : strcpy(s, sqlite3_column_name(ctx->sl3Request, 0));
for(cpt = 0; cpt < cols; cpt++)
dynStoreSz(e, record, nb, cpt + 1, (char *)sqlite3_column_text(ctx->sl3Cursor, cpt), DYN_LGNONE, cFM, cVM);
}
if(cr != SQLITE_DONE && cr != SQLITE_ROW)
return SL3ERR_FETCH;
else
return nb;
}
WAPIDECL long createTableSl3(env * e, modCtxSl3 * ctx, char * table, Dynamic * colName, Dynamic * colType, long nbPk)
{
sqlite3_finalize(ctx->sl3Request);
/* exemple
CREATE TABLE ftest (kcust INTEGER, kind INTEGER, ident TEXT,
CONSTRAINT ftrans_pk PRIMARY KEY (kcust,kind));
*/
/* colName et colType en VM, separateur = ',' ; type = TEXT/INTEGER */
dynLet(e, &ctx->request, "CREATE TABLE ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, " (", DYN_LGNONE);
long col, nbCol = dynDcount(e, colName, ',', DYN_NONE, DYN_NONE);
if(nbCol <= 0)
return SL3ERR_NOTABLEINFO;
if(nbPk <= 0 || nbPk > nbCol)
return SL3ERR_NOPK;
for(col = 1; col <= nbCol; col++)
{
dynField(e, colName, &ctx->colAll, col, DYN_NONE, ',', DYN_NONE, 1);
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, " ", DYN_LGNONE);
dynField(e, colType, &ctx->colAllType, col, DYN_NONE, ',', DYN_NONE, 1);
dynConcat(e, &ctx->request, &ctx->colAllType);
if(col > 1)
dynConcatSz(e, &ctx->request, ",", DYN_LGNONE);
}
/* les <nbPk> premieres colonnes sont la cle primaire, dans l'ordre */
dynConcatSz(e, &ctx->request, ", CONSTRAINT ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
dynConcatSz(e, &ctx->request, "_pk PRIMARY KEY (", DYN_LGNONE);
dynField(e, colName, &ctx->colAll, col, DYN_NONE, ',', DYN_NONE, nbPk); // les <nbPk> premieres colonnes sont la cle primaire, dans l'ordre
dynConcat(e, &ctx->request, &ctx->colAll);
dynConcatSz(e, &ctx->request, "))", DYN_LGNONE);
/* */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
int cr = sqlite3_step(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Request);
if(cr == SQLITE_DONE)
return OK;
else
return SL3ERR_STEP;
}
WAPIDECL long removeTableSl3(env * e, modCtxSl3 * ctx, char * table)
{
remove_rwSl3(e, ctx, table);
/* */
sqlite3_finalize(ctx->sl3Request);
dynLet(e, &ctx->request, "DROP TABLE ", DYN_LGNONE);
dynConcatSz(e, &ctx->request, table, DYN_LGNONE);
/* */
if(sqlite3_prepare_v2(ctx->sl3Handle, ctx->request.mPtr, -1, &ctx->sl3Request, NULL) != SQLITE_OK) return SL3ERR_PREPARE;
int cr = sqlite3_step(ctx->sl3Request);
sqlite3_finalize(ctx->sl3Request);
if(cr == SQLITE_DONE)
return OK;
else
return SL3ERR_STEP;
}
/*
1 base = 1 fichier sur disque (rm pour supprimer la base...), open ouvre ou cree la base (il suffit de verifier si le fichier existe...). Encodage = UTF-8
pas d'asynchrone (creer des threads/process) ; PRAGMA table_info(<table>) donne les infos sur une table (colonnes, types, PK etc.) ; pas de notion de schema (tout est dans la meme "base")
syntaxe pour binding dans requetes : ?1 ?2 ou :param1 $param2 @param3
docs : https://sqlite.org/capi3ref.html
sqlite3.c: The SQLite amalgamation source file
sqlite3.h: The header file that accompanies sqlite3.c and defines the C-language interfaces to SQLite.
shell.c: The command-line interface program itself.
gcc -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION shell.c sqlite3.c -lm -o sqlite3
gcc -fPIC -shared sqlite3.c -o libsqlite3.so -lpthread -ldl -lm
*/
+79
View File
@@ -0,0 +1,79 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include <libssh/libssh.h>
#include <libssh/sftp.h>
/* codes a passer a la fonction setError */
enum {
WSSH_MEM_ERROR = -2,
WSSH_ERROR = -1,
WSSH_OK = 0,
WSSH_SESSION = 1,
WSSH_SESSION_CONNECT = 2,
WSSH_AUTH = 3,
WSSH_CHANNEL = 4,
WSSH_CHANNEL_OPEN = 5,
WSSH_WRITE = 6,
WSSH_READ = 7,
WSSH_EXEC = 8,
WSSH_MODE = 9,
WSSH_SFTP = 10,
WSSH_SFTP_INIT = 11
};
enum {
WSSH_EXEC_MODE = 1,
WSSH_TERMINAL_MODE = 0
};
typedef struct {
ssh_session session;
ssh_channel channel; /* commandes console */
sftp_session sftp;
/* */
int err; /* erreur specifique au module */
int packet; /* taille des paquets lus un par un */
int execMode; /* TRUE si channelExec, FALSE si pseudo terminal */
} modContextSsh;
WAPIDECL void initSsh(env * e, modContextSsh * ctx);
WAPIDECL void freeSsh(env * e, modContextSsh * ctx);
WAPIDECL long setSession(env * e, modContextSsh * ctx, Dynamic * host, Dynamic * user, Dynamic * pwd);
WAPIDECL void freeSession(env * e, modContextSsh * ctx);
WAPIDECL long setChannel(env * e, modContextSsh * ctx, int mode);
WAPIDECL void freeChannel(env * e, modContextSsh * ctx);
WAPIDECL long channelExec(env * e, modContextSsh * ctx, Dynamic * data, Dynamic * resultat, number timeout);
WAPIDECL long channelWrite(env * e, modContextSsh * ctx, Dynamic * data);
WAPIDECL long channelRead(env * e, modContextSsh * ctx, Dynamic * data, number timeout);
/* faire idem channel pour "transfert" (sftp) */
WAPIDECL long setSftp(env * e, modContextSsh * ctx);
WAPIDECL void freeSftp(env * e, modContextSsh * ctx);
+310
View File
@@ -0,0 +1,310 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include "langage.h"
#include "dynamic.h"
#include "var.h"
#include "ssh.h"
typedef struct {
int error; /* dernier code erreur specifique au module */
//***
modContextSsh ctxSsh;
} modEtat;
enum {
EXMOD_WSSH_SESSION = 1,
EXMOD_WSSH_CHANNEL = 2,
EXMOD_WSSH_SFTP = 3,
EXMOD_WSSH_WRITECHANNEL = 4,
EXMOD_WSSH_EXECCHANNEL = 5,
EXMOD_WSSH_READCHANNEL = 6
};
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;
//***
initSsh(e, &p_etat->ctxSsh);
}
}
else if(modFnIs(e, "end", 3))
{
// liberation specifique au module avant arret process
p_etat = (modEtat *)(*etat);
if(p_etat != NULL)
{
freeSsh(e, &p_etat->ctxSsh);
//***
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->ctxSsh.err);
}
else
exc = EX_MODPARAM; // variable en parametre du mauvais type
}
}
/* ============================================================================================= */
else if(modFnIs(e, "openSession", 11))
{
/* ouvre la connexion ssh au serveur */
if(p_etat == NULL)
return (exc = EX_MODETAT);
else 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
{
// param1 = host, param2 = user, param3 = password
if(setSession(e, &p_etat->ctxSsh, param1, param2, param3) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SESSION);
else
exc = OK;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "endSession", 10))
{
/* ferme la connexion ssh au serveur */
if(p_etat == NULL)
return (exc = EX_MODETAT);
else
{
freeSession(e, &p_etat->ctxSsh);
exc = OK;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "execChannel", 11))
{
/* envoi d'une commande "one shot" (param1), pas besoin du 'openChannel' ici, lecture du resultat avec 'readChannel' et renvoi du resultat dans param2, timeout en sec. dans param3 */
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_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if(var_conv_num(e, param3, &timeout))
{
if(channelExec(e, &p_etat->ctxSsh, param1, param2, timeout) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_EXECCHANNEL);
else
exc = OK;
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "openChannel", 11))
{
/* ouvre un canal de type "terminal" avec le serveur
faire un 'readChannel' la premiere fois apres le 'openChannel', puis enchainer les ecritures (commandes) et lectures (resultat)
*/
if(p_etat == NULL)
return (exc = EX_MODETAT);
else
{
if(setChannel(e, &p_etat->ctxSsh, WSSH_TERMINAL_MODE) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_CHANNEL);
else
exc = OK;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "writeChannel", 12))
{
/* envoi d'une commande au pseudo-terminal */
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(channelWrite(e, &p_etat->ctxSsh, param1) != WSSH_OK)
{
exc = setError(p_etat, EXMOD_WSSH_WRITECHANNEL);
}
else
exc = OK;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "readChannel", 11))
{
/* lecture du resultat d'une commande (stdout dans param1) en mode terminal, timeout en sec. dans param2 */
if(p_etat == NULL)
exc = EX_MODETAT;
else if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_DYNAMIC)
exc = EX_MODPARAM;
else
{
number timeout;
if(var_conv_num(e, param2, &timeout))
{
if(channelRead(e, &p_etat->ctxSsh, param1, timeout) != WSSH_OK)
{
exc = setError(p_etat, EXMOD_WSSH_READCHANNEL);
}
else
exc = OK;
}
else
exc = EX_MODPARAM;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeChannel", 12))
{
/* ferme le channel mais laisse la connexion au serveur ouverte (mode terminal seulement, inutile en mode exec) */
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
freeChannel(e, &p_etat->ctxSsh);
exc = OK;
}
}
/* ============================================================================================= */
else if(modFnIs(e, "openSftp", 8))
{
/* ouvre un canal de type "transfert" avec le serveur */
if(p_etat == NULL)
return (exc = EX_MODETAT);
else
{
if(setSftp(e, &p_etat->ctxSsh) != WSSH_OK)
exc = setError(p_etat, EXMOD_WSSH_SFTP);
else
exc = OK;
}
}
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "closeSftp", 9))
{
/* ferme le canal "transfert" mais laisse la connexion au serveur ouverte */
if(p_etat == NULL)
exc = EX_MODETAT;
else
{
freeSftp(e, &p_etat->ctxSsh);
exc = OK;
}
}
/* ----------------------------------------------------------------------------------------------- */
else
{
if(p_etat == NULL)
exc = EX_MODETAT;
else
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
}
//
return exc;
}
+292
View File
@@ -0,0 +1,292 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include "ssh.h"
#ifdef WINLIB
#include <WinSock2.h>
#else
#include "poll.h"
#endif
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ---------------------------------------------------- */
/*
unix : -lssh -lcrypto -lssl -lz (dependances openssl zlib, verification avec : ldd /usr/lib/libssh.so)
sudo apt update
sudo apt install -y \
openssl libssl-dev \
zlib1g zlib1g-dev \
libssh-dev
openssl → binaire en ligne de commande
libssl-dev → headers + librairies pour compiler en C
zlib1g → runtime
zlib1g-dev → headers (zlib.h) + .so
libssh-dev → headers et libs de développement
windows : libssh.lib (et libssh compile avec msvc sinon ko)
ajouter => libssl.lib libcrypto.lib zlib.lib ws2_32.lib (car dependances openssl, zlib, socket)
git clone https://github.com/microsoft/vcpkg
cd vcpkg
bootstrap-vcpkg.bat
vcpkg install libssh:x64-windows
vcpkg install zlib:x64-windows
vcpkg install openssl:x64-windows
+ compil/link => cl main.c /I"path\to\vcpkg\installed\x64-windows\include" /link /LIBPATH:"path\to\vcpkg\installed\x64-windows\lib" libssh.lib libssl.lib libcrypto.lib zlib.lib ws2_32.lib
=> repertoire ou se trouve vcpkg (install depuis git) :
C:\Users\Poupougne42\source\vcpkg-master\installed\x64-windows
À l'exécution il faut :
libssl-*.dll
libcrypto-*.dll
dans :
même dossier que .exe ou dans le PATH
=== CERTIFICAT auto signé
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes
openssl req -x509 -newkey rsa:2048 -keyout server.key -out server.crt -days 365 -nodes
avec windows, c'est pareil, sauf initsocket WAStartup, type SOCKET et pas int, closesocket() et il faut fournir un fichier ca (https://curl.se/ca/cacert.pem) pour la verification des certificats
https://kb.firedaemon.com/...openssl-binary-distributions : binaires openssl sous windows (3.5.6 LTS ok), ok avec libssh 0.12.x (eventuellement 0.11.x)
*/
/* ****** PRIVATE ************************ */
int ssh_read_timeout(env * e, modContextSsh * ctx, Dynamic * data, number timeout)
{
#ifndef WINLIB
struct pollfd fd;
fd.fd = ssh_get_fd(ctx->session),
fd.events = POLLIN;
/* lecture avec timeout */
int cr = poll(&fd, 1, timeout * 1000 / NUM_FACTEUR);
#else
WSAPOLLFD fd;
fd.fd = (SOCKET)ssh_get_fd(ctx->session);
fd.events = POLLRDNORM;
fd.revents = 0;
/* lecture avec timeout */
int cr = WSAPoll(&fd, 1, timeout * 1000 / NUM_FACTEUR);
#endif
if (cr == 0)
return SSH_AGAIN; /* pas de donnees ou timeout */
if (cr < 0)
return SSH_ERROR;
/* lecture des donnees presentes */
return ssh_channel_read(ctx->channel, data->mPtr + data->mLg, ctx->packet, 0); /* 0 signifie lire stdout, 1 pour stderr */
}
/* ****** PUBLIC ************************ */
WAPIDECL void initSsh(env * e, modContextSsh * ctx)
{
ctx->packet = 16000;
ctx->execMode = WSSH_EXEC_MODE; /* for channel management */
ctx->channel = NULL;
ctx->session = NULL;
}
WAPIDECL void freeSsh(env * e, modContextSsh * ctx)
{
freeSession(e, ctx);
}
WAPIDECL long setSession(env * e, modContextSsh * ctx, Dynamic * host, Dynamic * user, Dynamic * pwd)
{
freeSession(e, ctx);
/* */
if((ctx->session = ssh_new()) == NULL)
return (ctx->err = WSSH_SESSION);
/* */
ssh_options_set(ctx->session, SSH_OPTIONS_HOST, host->mPtr);
ssh_options_set(ctx->session, SSH_OPTIONS_USER, user->mPtr);
/* */
if(ssh_connect(ctx->session) != SSH_OK)
{
ssh_free(ctx->session);
ctx->session = NULL;
return (ctx->err = WSSH_SESSION_CONNECT);
}
/* */
if(ssh_userauth_password(ctx->session, NULL, pwd->mPtr) != SSH_AUTH_SUCCESS)
{
//ssh_channel_free(ctx->channel);
freeSession(e, ctx);
return (ctx->err = WSSH_AUTH);
}
return (ctx->err = WSSH_OK);
}
WAPIDECL void freeSession(env * e, modContextSsh * ctx)
{
freeChannel(e, ctx);
freeSftp(e, ctx);
if(ctx->session)
{
ssh_disconnect(ctx->session);
ssh_free(ctx->session);
ctx->session = NULL;
}
}
WAPIDECL long setChannel(env * e, modContextSsh * ctx, int mode)
{
freeChannel(e, ctx);
ctx->execMode = mode;
ssh_set_blocking(ctx->session, TRUE); /* bloquant */
/* */
if((ctx->channel = ssh_channel_new(ctx->session)) == NULL)
return (ctx->err = WSSH_CHANNEL);
/* */
if(ssh_channel_open_session(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
if(ctx->execMode == WSSH_EXEC_MODE)
return (ctx->err = WSSH_OK);
/* */
/* Allocation d'un pseudo-terminal + shell interactif (channel reste ouvert dans ce cas) */
if(ssh_channel_request_pty(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
if(ssh_channel_request_shell(ctx->channel) != SSH_OK)
{
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
return (ctx->err = WSSH_CHANNEL_OPEN);
}
return (ctx->err = WSSH_OK);
}
WAPIDECL void freeChannel(env * e, modContextSsh * ctx)
{
if(ctx->channel)
{
if(ctx->execMode == WSSH_TERMINAL_MODE)
{
ssh_channel_write(ctx->channel, "exit\n", 5);
ssh_channel_send_eof(ctx->channel);
}
ssh_channel_close(ctx->channel);
ssh_channel_free(ctx->channel);
ctx->channel = NULL;
}
}
WAPIDECL long channelExec(env * e, modContextSsh * ctx, Dynamic * data, Dynamic * resultat, number timeout)
{
long cr;
cr = setChannel(e, ctx, WSSH_EXEC_MODE);
if(cr != WSSH_OK)
return (ctx->err = cr);
/* send command to channel, one shot (ssh_channel_request_exec ferme le channel a chaque commande) */
if(ssh_channel_request_exec(ctx->channel, data->mPtr) != SSH_OK)
cr = (ctx->err = WSSH_EXEC);
else
cr = channelRead(e, ctx, resultat, timeout); /* lecture du resultat en mode bloquant suite a l'envoi de la requete */
/* */
return cr;
}
WAPIDECL long channelWrite(env * e, modContextSsh * ctx, Dynamic * data)
{
if(ctx->execMode != WSSH_TERMINAL_MODE)
return (ctx->err = WSSH_MODE);
/* send command to channel */
if(ssh_channel_write(ctx->channel, data->mPtr, data->mLg) < 0)
return (ctx->err = WSSH_WRITE);
else
return (ctx->err = WSSH_OK);
/* le channel reste ouvert */
}
WAPIDECL long channelRead(env * e, modContextSsh * ctx, Dynamic * data, number timeout)
{
ssh_set_blocking(ctx->session, FALSE); /* non bloquant */
/* read response from serveur */
dynSetLen(e, data, 0);
/* Lire la sortie, mode non bloquant ici (explicite avec read_nonblocking) */
for(;;)
{
if(dynCtrl(e, data, data->mLg + ctx->packet, TRUE))
{
return (ctx->err = WSSH_MEM_ERROR); /* erreur memoire */
}
int nb = ssh_read_timeout(e, ctx, data, timeout);
/* */
if(nb == SSH_ERROR)
return (ctx->err = WSSH_READ);
if(nb == SSH_AGAIN || nb == 0)
return (ctx->err = WSSH_OK); /* rien a lire pour l'instant ou sortie en timeout ou fin des donnees */
/* */
if(nb > 0)
dynSetLen(e, data, data->mLg + nb);
/* continue reading */
}
}
WAPIDECL long setSftp(env * e, modContextSsh * ctx)
{
if((ctx->sftp = sftp_new(ctx->session)) == NULL)
return (ctx->err = WSSH_SFTP);
/* */
if(sftp_init(ctx->sftp) != SSH_OK)
{
freeSftp(e, ctx);
return (ctx->err = WSSH_SFTP_INIT);
}
return (ctx->err = WSSH_OK);
}
/*
sftp_file file = sftp_open(sftp, "/etc/hostname", O_RDONLY, 0); // NULL : erreur open
nbytes = sftp_read(file, buffer, sizeof(buffer)); // tant que nbytes > 0
sftp_close(file);
*/
WAPIDECL void freeSftp(env * e, modContextSsh * ctx)
{
if(ctx->sftp)
{
sftp_free(ctx->sftp);
ctx->sftp = NULL;
}
}
+23 -16
View File
@@ -153,9 +153,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
p_etat->error = 0;
// execute(command, returning, capturing)
// pour les vars en sortie, forcer le chgt de type si besoin ?
if(!param1 || param1->type != VAR_DYNAMIC)
if(param1 == NULL || param2 == NULL)
exc = EX_MODPARAM;
else if(!param2 || param2->type != VAR_NUMBER)
else if(param1->type != VAR_DYNAMIC || param2->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
@@ -207,9 +207,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
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
{
@@ -232,9 +232,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
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
{
@@ -267,9 +267,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
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
{
@@ -295,7 +295,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
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
{
@@ -320,7 +322,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
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
{
@@ -350,9 +354,9 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
// 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
{
@@ -522,17 +526,20 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
/* ----------------------------------------------------------------------------------------------- */
else if(modFnIs(e, "sleep", 5))
{
if(param1 == NULL)
exc = EX_MODPARAM;
else if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
else
{
#ifdef WINLIB
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
// duree attente envoyee en secondes
Sleep(param1->num * 1000 / NUM_FACTEUR); // en millisec.
#else
if(param1->type != VAR_NUMBER)
exc = EX_MODPARAM;
// duree attente envoyee en secondes, avec les decimales
usleep(param1->num * (1000000 / NUM_FACTEUR)); // en microsec.
#endif
}
}
/* ----------------------------------------------------------------------------------------------- */
else
+26 -10
View File
@@ -2,7 +2,7 @@
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024,2025 lanisys.fr
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
@@ -27,6 +27,7 @@
#include "langage.h"
#include "dynamic.h"
#include "var.h"
typedef struct {
int error; // dernier code erreur specifique au module
@@ -41,7 +42,7 @@ static int setError(modEtat * p, int err)
{
if(p != NULL)
p->error = err;
return EX_MODERR;
return err == OK ? OK : EX_MODERR;
}
#ifdef WINLIB
@@ -51,7 +52,6 @@ __declspec(dllexport) long execModule(env * , var * , var * , var * , void ** );
long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
{
/* TODO : gestion des 3 parametres (au lieu d'un seul) */
modEtat * p_etat;
long exc = OK;
// init/end/vers/error sont obligatoires pour tout module
@@ -84,13 +84,16 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
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);
@@ -125,18 +128,31 @@ long execModule(env * e, var * param1, var * param2, var * param3, void ** etat)
exc = EX_MODPARAM; // bad type of parameter
}
}
else if(p_etat == NULL)
{
exc = EX_MODETAT;
}
/* ============================================================================================= */
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);
/* 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
{
setError(p_etat, 0); // evite un warning de compil
exc = EX_MODFUNC; // fonction non prise en charge
exc = setError(p_etat, EX_MODFUNC); // fonction non prise en charge
}
//
return exc;
}
+23 -3
View File
@@ -30,19 +30,23 @@
#include "var.h"
/* programme de test unitaire de lib/fonctions */
/* gcc w_src/test.c -s -o exec/test -Wall -m64 -DUNIX -L./exec -l:libw.so -l:encod_lib.so */
/* gcc w_src/test.c -s -o exec/test -Wall -m64 -DUNIX -L./exec -l:libw.so -l:cipher_lib.so */
#include "encod.h"
#include "convert.h"
#include "cipher.h"
env e;
modContextCipher ctx;
int main(int argc, char * argv[])
{
init_env(&e);
//
Dynamic v, w;
Dynamic v, w, x;
dynInit(&e, &v, DYN_LGMIN);
dynInit(&e, &w, DYN_LGMIN);
dynInit(&e, &x, DYN_LGMIN);
//
dynLet(&e, &v, "test des encodages12", DYN_LGNONE);
printf("test base64: %s\n", v.mPtr);
@@ -56,8 +60,24 @@ int main(int argc, char * argv[])
hex2str(&e, &v, &w);
printf("hexa2str: %s\n", w.mPtr);
//
dynLet(&e, &v, "x#11yugjh#HDxxx", DYN_LGNONE);
long cr = dynEscapeHexaMark(&e, &v);
printf("escape hexamark (cr %ld): *%s* lg %lld\n", cr, v.mPtr, v.mLg);
//
cipherInit(&e, &ctx);
dynLet(&e, &x, "cle1234567890123", DYN_LGNONE);
dynLet(&e, &v, "ABCDEFGHIJKLMNOP123456", DYN_LGNONE);
printf("\ncipher_aes128: %s cle: %s\n", v.mPtr, x.mPtr);
cr = cipher_AES128(&e, &ctx, &x, &v, &w);
printf("lg chiffre: %lld cr:%ld\n", w.mLg, cr);
dynSetLen(&e, &v, 0);
cr = decipher_AES128(&e, &ctx, &x, &w, &v);
printf("decipher_aes128 (lg: %lld): *%s* cr:%ld\n", v.mLg, v.mPtr, cr);
cipherEnd(&e, &ctx);
//
dynFree(&e, &v);
dynFree(&e, &w);
dynFree(&e, &x);
//
return 0;
}
+42 -17
View File
@@ -120,11 +120,11 @@ WAPIDECL int varptrtbl_ctrl(env * e, var * v)
return FALSE;
/*
format de varptrtbl : toutes les entrees sont de 8 octets
v[1] = nb, v[2] = ad ptr, v[3] = ptr sur la var param, v[4] = ad ptr 2, etc.
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;
pointeur * curr = beg + 2;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v->ptr)
return TRUE; // deja existant
@@ -134,7 +134,7 @@ WAPIDECL int varptrtbl_ctrl(env * e, var * v)
return FALSE;
}
WAPIDECL void varptrtbl_add(env * e, var * v)
WAPIDECL void varptrtbl_maj(env * e, var * v)
{
// ajoute a e->varptrtbl la var si de type "pointeur" : VAR_PARAM, objet...
if(v == NULL)
@@ -143,15 +143,19 @@ WAPIDECL void varptrtbl_add(env * e, var * v)
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.
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->ptr)
return; // deja existant : RAS
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
@@ -160,14 +164,14 @@ WAPIDECL void varptrtbl_add(env * e, var * v)
beg = (pointeur *)e->varptrtbl.ptr; // au cas ou realloc memoire
*((ent64 *)beg) = addnb;
curr = beg + addnb * 2;
*curr-- = (pointeur)v;
*curr = (pointeur)v->ptr;
*curr-- = (pointeur)v->ptr;
*curr = (pointeur)v;
}
}
WAPIDECL void varptrtbl_del(env * e, var * v)
{
// supprime de e->varptrtbl la var v
// supprime de e->varptrtbl la var param v
if(v == NULL)
return;
/*
@@ -179,7 +183,7 @@ WAPIDECL void varptrtbl_del(env * e, var * v)
pointeur * curr = ++beg;
ent64 savnb = nb;
while(nb--)
if((pointeur *)(*curr) == (pointeur *)v->ptr)
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;
@@ -197,10 +201,13 @@ WAPIDECL void varptrtbl_del(env * e, var * v)
WAPIDECL int var_conv_num(env * e, var * v, number * num)
{
if(!v || !num)
if(v == NULL || num == NULL)
return FALSE;
if(v->type == VAR_PARAM)
v = (var *)v->ptr;
{
if((v = (var *)v->ptr) == NULL)
return FALSE;
}
if(v->type == VAR_NUMBER)
{
*num = v->num;
@@ -220,7 +227,13 @@ WAPIDECL void var_free(env * e, var * v, int suivre_par)
if(v == NULL)
return;
if(suivre_par && v->type == VAR_PARAM)
v = (var *)v->ptr; /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
if((v = (var *)v->ptr) == NULL) /* travailler avec la var pointee ! verifier le pointeur avec "var_ctrl_param(e, v);" */
{
e->exception = EX_VARPARAM_KO;
return;
}
}
/* rien a liberer sur vars NULL, NUMBER et PARAM (ce dernier cas n'est pas possible) */
switch(v->type)
{
@@ -255,11 +268,23 @@ 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
@@ -288,7 +313,7 @@ WAPIDECL void var_let(env * e, var * let, var * v, int suivre_let, int suivre_v)
break;
//
case VAR_PARAM:
if(!suivre_v)
if(!suivre_v) // ??
var_init(e, let, VAR_PARAM, 0, 0, v->ptr);
break;
+1 -1
View File
@@ -31,7 +31,7 @@ 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_add(env * e, var * v);
WAPIDECL void varptrtbl_maj(env * e, var * v);
WAPIDECL void varptrtbl_del(env * e, var * v);
/* ********************************************** */
+5 -2
View File
@@ -51,7 +51,7 @@ input: input
declare: declare
let: let
delet: delet ; unlet ??
delet: delet
new: new
class: class
@@ -66,6 +66,8 @@ frac: frac
abs: abs
neg: neg
round: round
sqrt: sqrt
exp: exp
type: type
len: len
@@ -74,6 +76,7 @@ dcount: dcount
field: field
index: index
search: search
sortedsearch: sortedsearch
change: change
format: format
insert: insert
@@ -101,7 +104,7 @@ ends: (1,1,#5D) ; ]
indirect: !
typeof: ? ; typeof ??
typeof: typeof ; typeof x.y.z
stringdq: (1,1,#22) (0,765,#20-#21#23-#EF) (1,1,#22) ; contenu chaine : car car car #FF (en majuscule), a verifier lors du parse (hexa -> binaire + controle)
stringq: (1,1,#27) (0,765,#20-#26#28-#EF) (1,1,#27) ; idem
+91
View File
@@ -0,0 +1,91 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include "langage.h"
#include "dynamic.h"
// --- gestion protocole websocket (http + protocole binaire specifique)
typedef struct {
int state; /* etat de decodage des trames http/ws : 0 entete a lire, 1 en cours lecture entete, 2 lecture corps websocket binaire */
ent64s lengthToRead; /* longueur de donnees (corps, frame header) restant a lire */
Dynamic header; /* liste des entetes http <1,x> nom entete (minuscule) <2, x> valeur, le decodage de la premiere ligne est mis ici : http_method http_path http_vers */
Dynamic content; /* corps du message binaire ws */
Dynamic contentControl; /* content control frame found in fragment */
Dynamic line, tmp; /* buffer de lecture d'une ligne, variable de travail */
Dynamic frameHeader; /* 14 octets utilises maxi */
int finalFrame, mask, opcode, len, fragment, opcodeFragment, controlInFragment;
octet maskey[4];
int error;
} modCtxWs;
enum {
/* state */
WSSTATE_HEADERTOREAD = 0,
WSSTATE_READINGHEADER = 1,
WSSTATE_READINGFRAMEHEADER = 2,
WSSTATE_READINGFRAMEHEADEREXT = 3,
WSSTATE_READINGFRAMECONTENT = 4,
/* codes d'erreur */
WS_METHOD_KO = 1,
WS_METHOD_VERSION_KO = 2,
WS_INCORRECT_LENGTH = 3,
WS_COLON_MISSING = 4,
WS_MISSING_HEADER = 5,
WS_MISSING_MASK = 6,
WS_OPCODE_KO = 7,
WS_FRAGMENT_KO = 8,
WS_LENGTH_TOO_HIGH = 9,
WS_MEMORY = 10,
/* code retour */
WS_REQUEST_ERROR = -1,
WS_REQUEST_INPROGRESS = 0,
WS_REQUEST_COMPLETE = 1,
WS_REQUEST_EXPECTCONTENT = 2,
WS_REQUEST_CLOSE = 3,
WS_REQUEST_PING = 4,
WS_REQUEST_PONG = 5,
WS_REQUEST_FRAGMENT = 6,
/* framing opcode */
WS_FRAME_OPCODE_TEXT = 1,
WS_FRAME_OPCODE_BINARY = 2,
WS_FRAME_OPCODE_CLOSE = 8,
WS_FRAME_OPCODE_PING = 9,
WS_FRAME_OPCODE_PONG = 10,
/* framing fragment */
WS_FRAME_FRAGMENT_ON = 0,
WS_FRAME_FRAGMENT_OFF = 1,
WS_FRAME_MASK_ON = 1,
WS_FRAME_MASK_OFF = 0
};
WAPIDECL void Init(env * e, modCtxWs * ctx);
WAPIDECL void End(env * e, modCtxWs * ctx);
WAPIDECL long ExtractMessage(env * e, modCtxWs * ctx, Dynamic * data);
WAPIDECL long MakeExpectContent(env * e, modCtxWs * ctx, Dynamic * reponse);
WAPIDECL long MakeFrame(env * e, modCtxWs * ctx, int frameType, Dynamic * data, Dynamic * response);
+475
View File
@@ -0,0 +1,475 @@
/* **********************************************
__ __ __
\ \/ \/ / W language
\ /\ /
\/ \/ Copyright 2024-2026 lanisys.fr
This file is part of W language.
W language is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (GPL-3.0-or-later).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
********************************************** */
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "websocket.h"
#include "convert.h"
#include "hash.h"
// force exporting
#ifdef WINLIB
#undef WAPIDECL
#define WAPIDECL __declspec(dllexport)
#else
#undef WAPIDECL
#define WAPIDECL
#endif
/* ***** PRIVATE *************** */
#define CRLF "\r\n"
#define LEN_CRLF 2
static int HeaderCheck(env * e, modCtxWs * ctx, char * headerName, char * headerValue)
{
long posEntete = dynLocateSz(e, &ctx->header, headerName, cVM, 1, cFM);
if(posEntete == DYN_NOTLOCATED)
return FALSE;
/* */
dynField(e, &ctx->header, &ctx->tmp, 1, posEntete, cFM, cVM, 1);
if(headerValue)
{
str2lower(e, &ctx->tmp);
return dynCompare(e, &ctx->tmp, CMP_EQ, headerValue, DYN_LGNONE);
}
else
return TRUE;
}
/* ***** PUBLIC *************** */
WAPIDECL void Init(env * e, modCtxWs * ctx)
{
ctx->error = 0;
ctx->state = WSSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
ctx->fragment = FALSE; /* TRUE if fragmentation is on */
ctx->controlInFragment = FALSE;
dynInit(e, &ctx->header, DYN_LGMIN);
dynInit(e, &ctx->content, DYN_LGMIN);
dynInit(e, &ctx->contentControl, DYN_LGMIN);
dynInit(e, &ctx->line, DYN_LGMIN);
dynInit(e, &ctx->tmp, DYN_LGMIN);
dynInit(e, &ctx->frameHeader, DYN_LGMIN);
}
WAPIDECL void End(env * e, modCtxWs * ctx)
{
dynFree(e, &ctx->header);
dynFree(e, &ctx->content);
dynFree(e, &ctx->contentControl);
dynFree(e, &ctx->line);
dynFree(e, &ctx->tmp);
dynFree(e, &ctx->frameHeader);
}
WAPIDECL long ExtractMessage(env * e, modCtxWs * ctx, Dynamic * data)
{
/* lit les donnes et extrait un message avec son id : renvoi 1 quand le message est complet, 0 en attente de donnees, -1 erreur */
if(ctx->state == WSSTATE_HEADERTOREAD || ctx->state == WSSTATE_READINGHEADER)
{
for(;;)
{
long ind = dynIndexSz(e, data, CRLF, LEN_CRLF, 1);
if(ind < 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees (mettre un garde fou ici : si jamais de CRLF apres x octets, erreur et raz data) */
dynSetLen(e, &ctx->line, 0);
if(ind > 0)
dynSubstr(e, data, &ctx->line, 0, ind, DYN_NONE, DYN_NONE, DYN_NONE, DYN_NONE);
dynCut(e, data, ind + LEN_CRLF);
/* ici <ctx->line> contient la ligne d'entete et <data> est a jour avec les donnees suivantes */
/* */
if(ctx->state == WSSTATE_HEADERTOREAD)
{
/* premiere ligne du protocole */
dynField(e, &ctx->line, &ctx->tmp, 1, DYN_NONE, ' ', DYN_NONE, 1); // method
if(dynCompare(e, &ctx->tmp, CMP_NE, "GET", 3))
{
ctx->error = WS_METHOD_KO; /* seule GET autorisee */
return WS_REQUEST_ERROR; /* quand erreur, l'appelant doit vider le "conteneur" de donnee !? */
}
dynSetLen(e, &ctx->header, 0); // vider le header
dynInsSz(e, &ctx->header, 1, 1, "http_method", 11, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 2, DYN_NONE, ' ', DYN_NONE, 1); // path
dynInsSz(e, &ctx->header, 1, 1, "http_path", 9, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
//
dynField(e, &ctx->line, &ctx->tmp, 3, DYN_NONE, ' ', DYN_NONE, 1);
if(ctx->tmp.mLg == 0)
{
ctx->error = WS_METHOD_KO; /* seule GET autorisee et version doit etre presente */
return WS_REQUEST_ERROR;
}
else
{
dynInsSz(e, &ctx->header, 1, 1, "http_version", 12, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->tmp, cFM, cVM);
}
/* */
ctx->state = WSSTATE_READINGHEADER;
}
else
{
/* entetes a lire */
if(ctx->line.mLg == 0)
{
/* fin des entetes / entete typique ws =>
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
*/
dynSetLen(e, &ctx->content, 0);
if( ! HeaderCheck(e, ctx, "upgrade", "websocket"))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "connection", "upgrade"))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "host", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "origin", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "sec-websocket-version", "13"))
{
/* ici renvoyer une reponse 400 avec la valeur acceptee du serveur pour la version */
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
if( ! HeaderCheck(e, ctx, "sec-websocket-key", NULL))
{
ctx->error = WS_MISSING_HEADER; /* entete obligatoire non trouvee ou incorrecte pour ws */
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
/* ctx->tmp contient la clé codée en Base64 : calcul a faire pour renvoi au client */
dynConcatSz(e, &ctx->tmp, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36);
encodageSha1(e, &ctx->tmp, &ctx->line); // resultat en hexa ascii
hex2str(e, &ctx->line, &ctx->tmp); // binaire, à encoder en Base64
str2base64(e, &ctx->tmp, &ctx->line);
/* ajouter l'entete de reponse */
dynInsSz(e, &ctx->line, 1, DYN_NONE, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept:",
DYN_LGNONE, ' ', DYN_NONE);
dynConcatSz(e, &ctx->line, "\r\n\r\n", 4); /* fin de reponse http */
/* */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->lengthToRead = 2;
dynSetLen(e, &ctx->frameHeader, 0);
return WS_REQUEST_EXPECTCONTENT; /* envoyer la reponse (handshake) et attendre le contenu ws specifique */
}
else
{
/* lecture de l'entete */
dynBegin(e, &ctx->line);
if(dynNext(e, &ctx->line, &ctx->tmp, ':') > -1)
{
dynCut(e, &ctx->line, ctx->line.mInternal + 1);
// nom entete en minuscule
dynErase(e, &ctx->tmp, " ");
str2lower(e, &ctx->tmp);
if(dynLocateSz(e, &ctx->header, ctx->tmp.mPtr, cVM, 1, cFM) != DYN_NOTLOCATED)
continue; // entete deja memorisee, ignorer le doublon
// valeur
dynTrimSpace(e, &ctx->line);
// tmp = nom entete, line = valeur entete
dynIns(e, &ctx->header, 1, 1, &ctx->tmp, cFM, cVM);
dynIns(e, &ctx->header, 2, 1, &ctx->line, cFM, cVM);
}
else
{
/* erreur de syntaxe dans l'entete */
ctx->error = WS_COLON_MISSING;
ctx->state = WSSTATE_HEADERTOREAD;
return WS_REQUEST_ERROR;
}
}
}
} /* endless for */
}
/* */
/* a partir d'ici, une erreur provoque le retour a l'attente d'une entete de frame, pas d'entete html */
if(ctx->state == WSSTATE_READINGFRAMEHEADER)
{
/* lecture d'une requete WS : frame header 2 octets */
if(data->mLg == 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->frameHeader, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees d'entete sont lues, decodage de la frame */
dynConcatSz(e, &ctx->frameHeader, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
/* gerer la fragmentation ici (finalFrame), 1,2 ok, 8,9,10 possible au milieu mais non fragmente */
ctx->finalFrame = (ctx->frameHeader.ptr[0] & 1);
ctx->opcode = (ctx->frameHeader.ptr[0] >> 4);
/* fragment management */
if( ! ctx->fragment)
{
dynSetLen(e, &ctx->content, 0);
if(ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
; /* ras pas de fragmentation */
else if(ctx->opcode != WS_FRAME_OPCODE_TEXT && ctx->opcode != WS_FRAME_OPCODE_BINARY)
{
/* fragment non autorisee sur control frame ou opcode inconnu */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_FRAGMENT_KO;
return WS_REQUEST_ERROR;
}
else
{
/* debut de fragment */
ctx->fragment = TRUE;
ctx->opcodeFragment = ctx->opcode;
}
}
else
{
/* fragmentation en cours */
if(ctx->opcode == 0)
{
/* ras fragment suite ou fin */
if(ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
ctx->fragment = FALSE;
ctx->opcode = ctx->opcodeFragment;
}
else
{
if((ctx->opcode == WS_FRAME_OPCODE_CLOSE || ctx->opcode == WS_FRAME_OPCODE_PING || ctx->opcode == WS_FRAME_OPCODE_PONG)
&& ctx->finalFrame == WS_FRAME_FRAGMENT_OFF)
{
/* control frame autorisee au milieu de fragment */
ctx->controlInFragment = TRUE;
dynSetLen(e, &ctx->contentControl, 0);
}
else
{
/* opcode incorrect suite fragment suivant */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_FRAGMENT_KO;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
}
}
/* */
ctx->mask = (ctx->frameHeader.ptr[1] & 1);
ctx->len = (ctx->frameHeader.ptr[1] >> 1);
if( ! ctx->mask)
{
/* erreur : le client doit masquer tous ses messages */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_MISSING_MASK;
ctx->controlInFragment = FALSE;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
if( ctx->opcode != WS_FRAME_OPCODE_TEXT && ctx->opcode != WS_FRAME_OPCODE_BINARY &&
ctx->opcode != WS_FRAME_OPCODE_CLOSE && ctx->opcode != WS_FRAME_OPCODE_PING && ctx->opcode != WS_FRAME_OPCODE_PONG)
{
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->error = WS_OPCODE_KO; /* opcode inconnu/non pris en charge */
ctx->controlInFragment = FALSE;
ctx->fragment = FALSE;
return WS_REQUEST_ERROR;
}
if(ctx->len < 126)
ctx->lengthToRead = 4; /* masking key */
else if(ctx->len == 126)
ctx->lengthToRead = 6; /* longueur sur 2 octets a suivre (+ masking key) */
else
ctx->lengthToRead = 12; /* forcement 127 ici => longueur sur 8 octets a suivre (+ masking key) */
/* */
ctx->state = WSSTATE_READINGFRAMEHEADEREXT;
}
}
/* */
if(ctx->state == WSSTATE_READINGFRAMEHEADEREXT)
{
if(data->mLg == 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
/* lecture longueur si sur 2/8 octets + masking key */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, &ctx->frameHeader, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues, decodage de la frame */
dynConcatSz(e, &ctx->frameHeader, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
/* */
int posMaskey = 2;
if(ctx->len < 126)
ctx->lengthToRead = ctx->len;
else if(ctx->len == 126)
{
ctx->lengthToRead = (ent64s)ctx->frameHeader.ptr[2] + ((ent64s)ctx->frameHeader.ptr[3] << 8);
posMaskey = 4;
}
else
{
ctx->lengthToRead = (ent64s)ctx->frameHeader.ptr[2] + ((ent64s)ctx->frameHeader.ptr[3] << 8) ;
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[4] << 16) + ((ent64s)ctx->frameHeader.ptr[5] << 24);
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[6] << 32) + ((ent64s)ctx->frameHeader.ptr[7] << 40);
ctx->lengthToRead += ((ent64s)ctx->frameHeader.ptr[8] << 48) + ((ent64s)ctx->frameHeader.ptr[9] << 56);
posMaskey = 10;
}
memcpy(ctx->maskey, ctx->frameHeader.ptr + posMaskey, 4);
/* */
ctx->state = WSSTATE_READINGFRAMECONTENT;
}
}
/* */
if(ctx->state == WSSTATE_READINGFRAMECONTENT)
{
if(data->mLg == 0 && ctx->lengthToRead != 0)
return WS_REQUEST_INPROGRESS; /* en attente d'autres donnees */
if(data->mLg < ctx->lengthToRead)
{
/* une partie des donnees dispo */
dynConcat(e, ctx->controlInFragment ? &ctx->contentControl : &ctx->content, data);
ctx->lengthToRead -= data->mLg;
dynSetLen(e, data, 0);
return WS_REQUEST_INPROGRESS;
}
else
{
/* toutes les donnees sont lues */
if(ctx->lengthToRead != 0)
{
dynConcatSz(e, ctx->controlInFragment ? &ctx->contentControl : &ctx->content, data->mPtr, ctx->lengthToRead);
dynCut(e, data, ctx->lengthToRead);
}
/* appliquer le maskey a chaque octet lu */
if( ! ctx->controlInFragment)
for(long cpt = 0; cpt < ctx->content.mLg; cpt++)
ctx->content.ptr[cpt] ^= ctx->maskey[cpt % 4];
else
for(long cpt = 0; cpt < ctx->contentControl.mLg; cpt++)
ctx->contentControl.ptr[cpt] ^= ctx->maskey[cpt % 4];
/* ping : envoyer pong 0xA1, 0x00, pong ras, close couper la comm' + reset proto websocket */
ctx->state = WSSTATE_READINGFRAMEHEADER;
ctx->lengthToRead = 0;
ctx->controlInFragment = FALSE;
if(ctx->opcode == WS_FRAME_OPCODE_CLOSE)
return WS_REQUEST_CLOSE;
else if(ctx->opcode == WS_FRAME_OPCODE_PING)
return WS_REQUEST_PING;
else if(ctx->opcode == WS_FRAME_OPCODE_PONG)
return WS_REQUEST_PONG;
else
return (ctx->fragment ? WS_REQUEST_FRAGMENT : WS_REQUEST_COMPLETE);
}
}
/* */
ctx->state = WSSTATE_HEADERTOREAD;
ctx->lengthToRead = 0;
return WS_REQUEST_ERROR;
}
WAPIDECL long MakeExpectContent(env * e, modCtxWs * ctx, Dynamic * reponse)
{
dynLet(e, reponse, ctx->line.mPtr, ctx->line.mLg); /* handshake http before framing control */
return OK;
}
WAPIDECL long MakeFrame(env * e, modCtxWs * ctx, int frameType, Dynamic * data, Dynamic * response)
{
if(frameType != WS_FRAME_OPCODE_CLOSE && frameType != WS_FRAME_OPCODE_PING && frameType != WS_FRAME_OPCODE_PONG &&
frameType != WS_FRAME_OPCODE_TEXT && frameType != WS_FRAME_OPCODE_BINARY)
return WS_OPCODE_KO;
ent64s lg = 0;
if(data)
if((lg = data->mLg) > 65536ll * 65536ll)
return WS_LENGTH_TOO_HIGH; /* what if length too high : fragment ? refuse ? */
/* */
dynSetLen(e, response, 0);
response->ptr[0] = (frameType << 4) + WS_FRAME_FRAGMENT_OFF;
int posMaskey = 2;
if(lg < 126)
response->ptr[1] = (((octet)lg) << 1) + WS_FRAME_MASK_OFF; // only server mode, and so no masking
else if(lg < 65536)
{
response->ptr[1] = (((octet)126) << 1) + WS_FRAME_MASK_OFF;
response->ptr[2] = (octet)(lg & 255); /* 2 bytes, little endian */
response->ptr[3] = (octet)(lg >> 8);
posMaskey = 4;
}
else
{
response->ptr[1] = (((octet)127) << 1) + WS_FRAME_MASK_OFF;
response->ptr[2] = (octet)(lg & 255); /* 8 bytes, little endian */
response->ptr[3] = (octet)((lg >> 8) & 255);
response->ptr[4] = (octet)((lg >> 16) & 255);
response->ptr[5] = (octet)((lg >> 24) & 255);
response->ptr[6] = (octet)((lg >> 32) & 255);
response->ptr[7] = (octet)((lg >> 40) & 255);
response->ptr[8] = (octet)((lg >> 48) & 255);
response->ptr[9] = (octet)(lg >> 56);
posMaskey = 10;
}
/* for instance, no mask key */
if( ! dynCtrl(e, response, posMaskey + lg, TRUE))
{
dynSetLen(e, response, 0);
return WS_MEMORY;
}
if(lg > 0)
memcopie(response->ptr + posMaskey, data->ptr, lg);
dynSetLen(e, response, posMaskey + lg);
/* */
return OK;
}
+6 -3
View File
@@ -1,4 +1,4 @@
blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,type,53,len,54,count,55,dcount,56,field,57,index,58,search,59,change,60,format,61,insert,62,remove,63,tonum,64,tostring,65,equal,66,diff,67,gt,68,lt,69,gte,70,lte,71,and,72,or,73,not,74,beginpar,75,endpar,76,beginh,77,endh,78,begins,79,ends,80,indirect,81,typeof,82,stringdq,83,stringq,84,ident,85,varsys,86,numberdec,87,numberint,88,minus,89,plus,90,multiply,91,divide,92,divident,93,modulo,94,concat,95,listesep,96,identsep,97,modsep,98,other,99
blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,include,10,sub,11,endsub,12,if,13,then,14,else,15,elseif,16,endif,17,do,18,call,19,invoke,20,return,21,returnon,22,loop,23,endloop,24,foreach,25,in,26,like,27,endfor,28,break,29,breakon,30,continue,31,continueon,32,nop,33,part,34,echonl,35,echo,36,input,37,declare,38,let,39,delet,40,new,41,class,42,this,43,parent,44,hold,45,precision,46,setsep,47,int,48,frac,49,abs,50,neg,51,round,52,sqrt,53,exp,54,type,55,len,56,count,57,dcount,58,field,59,index,60,search,61,sortedsearch,62,change,63,format,64,insert,65,remove,66,tonum,67,tostring,68,equal,69,diff,70,gt,71,lt,72,gte,73,lte,74,and,75,or,76,not,77,beginpar,78,endpar,79,beginh,80,endh,81,begins,82,ends,83,indirect,84,typeof,85,stringdq,86,stringq,87,ident,88,varsys,89,numberdec,90,numberint,91,minus,92,plus,93,multiply,94,divide,95,divident,96,modulo,97,concat,98,listesep,99,identsep,100,modsep,101,other,102
1,-1,20:09
1,1,3B;0,-1,00-FF
1,1,62;1,1,65;1,1,67;1,1,69;1,1,6E
@@ -51,6 +51,8 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,61;1,1,62;1,1,73
1,1,6E;1,1,65;1,1,67
1,1,72;1,1,6F;1,1,75;1,1,6E;1,1,64
1,1,73;1,1,71;1,1,72;1,1,74
1,1,65;1,1,78;1,1,70
1,1,74;1,1,79;1,1,70;1,1,65
1,1,6C;1,1,65;1,1,6E
1,1,63;1,1,6F;1,1,75;1,1,6E;1,1,74
@@ -58,6 +60,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,66;1,1,69;1,1,65;1,1,6C;1,1,64
1,1,69;1,1,6E;1,1,64;1,1,65;1,1,78
1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68
1,1,73;1,1,6F;1,1,72;1,1,74;1,1,65;1,1,64;1,1,73;1,1,65;1,1,61;1,1,72;1,1,63;1,1,68
1,1,63;1,1,68;1,1,61;1,1,6E;1,1,67;1,1,65
1,1,66;1,1,6F;1,1,72;1,1,6D;1,1,61;1,1,74
1,1,69;1,1,6E;1,1,73;1,1,65;1,1,72;1,1,74
@@ -80,7 +83,7 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,5B
1,1,5D
1,1,21
1,1,3F
1,1,74;1,1,79;1,1,70;1,1,65;1,1,6F;1,1,66
1,1,22;0,765,20-21:23-EF;1,1,22
1,1,27;0,765,20-26:28-EF;1,1,27
1,1,61-7A:41-5A;0,23,61-7A:41-5A:30-39
@@ -97,4 +100,4 @@ blank,1,comment,2,begin,3,background,4,library,5,end,6,except,7,throw,8,catch,9,
1,1,2C
1,1,2E
1,1,26
1,1,00-FF
1,1,00-FF