subst et variables

13 views
Skip to first unread message

Pascal

unread,
Dec 29, 2008, 6:11:47 AM12/29/08
to
Bonjour,

Entre deux réveillons (que je vous souhaite des plus agréables), j'ai
quelques difficultés avec les variables composées, c'est-à-dire dont le
nom est le résultat de plusieurs paramètres. Un exemple :

set x un
set y deux
set undeux 12

Je veux récupérer $undeux depuis x et y. La seule solution que j'ai
trouvée :

puts "[subst $$x[subst $y]]"

Ne peut-on faire plus simple avec des (), {} ou autres ?

Dans le cas d'un array, si je veux récupérer $winX_docked($win), avec
set suffix _docked, je me trouve à écrire :

[subst $[subst winX$suffix]($win) ]

N'y a-t-il pas plus court ou lisible ?

Pascal Georges

Jack.R

unread,
Dec 29, 2008, 7:54:51 AM12/29/08
to

Plus court oui, plus lisible, à voir ...

set x un
set y deux
set undeux 12

puts [set $x$y]

Avec un array cela devrait donner (non testé)

puts [set winX$suffix($win)]

--
Jack.R

Kroc

unread,
Dec 29, 2008, 9:50:51 AM12/29/08
to
Dans ton premier cas, le plus simple c'est de faire comme Alain a
écrit :

puts [set $x$y]

Pour l'autre cas, le troisième alinéa de la règle 7 (voir http://wfr.tcl.tk/38)
répond à ta question : tu peux fixer le nom de la variable avec des
accolades. Dans ton cas, ça donne :

puts [set winX${suffix}($win)]

Mais :

Si tu en arrives à avoir ces noms de variables, c'est que tu
n'utilises probablement pas le bon type de variable pour stocker tes
données. Je pense que tu devrais jeter un coup d'oeil à http://wfr.tcl.tk/dict
qui devrait t'apporter la souplesse dont tu sembles avoir besoin.

--
David Zolli

Kroc

unread,
Dec 29, 2008, 11:21:37 AM12/29/08
to
Je détaille un poil l'usage de dict.

Pour le premier cas, ça donnerait :

% set x un
% set y deux
% dict set dico "$x $y" 12 ; # enregistre la valeur
% dict get $dico "$x $y" ; # lit la valeur enregistrée
12

Pour le deuxième cas :

% set win .fen
% set suffix docked
% dict set winX "$win $suffix" true
% dict get $winX "$win $suffix"
true

Ulis n'est plus là pour me remonter les bretelles, mais j'ai
volontairement utilisé des guillemets dans ces exemples pour que ça
soit plus facile à comprendre. La syntaxe idéale étant :

% dict set winX [list $win $suffix] true

Quant à [subst], il est très dangereux, comme le montre l'exemple
suivant (à ne surtout pas essayer !) :

set var {Je vais effacer tes données : [file delete -force ~]}
puts [subst {Vous avez entré la valeur $var.}]

On voit bien les dégâts que peut provoquer subst avec des variables
entrées par un utilisateurs sournois / idiot / malchanceux. En
particulier quand elles contiennent des crochets...

--
David Zolli

Kroc

unread,
Dec 30, 2008, 3:11:21 AM12/30/08
to
On 29 déc, 17:21, I wrote:
> Quant à [subst], il est très dangereux, comme le montre l'exemple
> suivant (à ne surtout pas essayer !) :
>
> set var {Je vais effacer tes données : [file delete -force ~]}
> puts [subst {Vous avez entré la valeur $var.}]
>
> On voit bien les dégâts que peut provoquer subst avec des variables
> entrées par un utilisateurs sournois / idiot / malchanceux. En
> particulier quand elles contiennent des crochets...

P.S.

Une solution simple pour se protéger contre ça c'est d'utiliser le
plus possible [subst -nocommands ...] plutôt que [subst ...] tout
seul.

--
David Zolli

Eric Hassold

unread,
Dec 30, 2008, 9:21:10 AM12/30/08
to
Bonjour,

Kroc a écrit :


> On 29 déc, 17:21, I wrote:
>> Quant à [subst], il est très dangereux, comme le montre l'exemple
>> suivant (à ne surtout pas essayer !) :

>> ...


> Une solution simple pour se protéger contre ça c'est d'utiliser le
> plus possible [subst -nocommands ...] plutôt que [subst ...] tout
> seul.

Que neni, helas!

% set var "code inclusion perverse \$tcl_platform(os\[puts AIE!\])"
% puts [subst -nocommand $var]

Et un beau "AIE!" qui apparait a l'ecran. Bien sur, un "file delete
-force ~" et autre [exec ...] encore plus destructeur sont possible a la
place du [puts], mais je ne voudrais pas que quelqu'un fasse un
copier-coller du code sans lire auparavant l'avertissement "SURTOUT NE
PAS EXECUTER".

Pour moi, ca s'apparente plus a un "bug" qu'a un "feature", mais
d'autre, dans d'autres discussions passees, pensaient differemment.

En tout cas, ce qu'il faut retenir: [subst -nocommand] ne PROTEGE PAS de
l'inclusion de code dangereux (ou pas) lors de la substitution. Donc si
la valeur de la chaine a substituer ne vient pas d'une source de
confiance (par ex. un formulaire web, etc...); revoyez tous vos code a
coup de "grep" pour reperer les [subst -nocommand] qui ne vous protege
pas malgre ce que le nom de l'option laisse penser.

Puis j'en profite:
Bonnes fetes a tous, que 2009 soit une annee pleine de bonheur et
Tcleusement votre.

Eric

-----
Eric Hassold
Evolane - http://www.evolane.com/


>
> --
> David Zolli

Pascal

unread,
Dec 30, 2008, 10:26:44 AM12/30/08
to
Kroc a écrit :

> Dans ton premier cas, le plus simple c'est de faire comme Alain a
> écrit :
>
> puts [set $x$y]
>
> Pour l'autre cas, le troisième alinéa de la règle 7 (voir http://wfr.tcl.tk/38)
> répond à ta question : tu peux fixer le nom de la variable avec des
> accolades. Dans ton cas, ça donne :
>
> puts [set winX${suffix}($win)]

Merci pour vos précisions, j'y vois plus clair. Seul détail, pourquoi

set x un
set y deux
set undeux 12

puts "$${x}${y}"


renvoit $undeux et non pas 12 ?

et là il est interdit d'utiliser une deuxième couche de {} comme :
puts "${${x}${y}}"

mais il est vrai que [set ...] fait bien le travail demandé, et mon code
fait "plus propre".

Pascal Georges

Pascal

unread,
Dec 30, 2008, 10:33:57 AM12/30/08
to
Eric Hassold a écrit :
> Bonjour,

> En tout cas, ce qu'il faut retenir: [subst -nocommand] ne PROTEGE PAS de
> l'inclusion de code dangereux (ou pas) lors de la substitution.

Eric, ce n'est pas la première fois que tu parles de ce risque... mais
ce n'est que maintenant que je comprends !

J'ai maintenant d'autres raisons que la lisibilité d'éviter "subst".

Pascal

Kroc

unread,
Dec 30, 2008, 1:12:25 PM12/30/08
to
On 30 déc, 16:26, Pascal <pas...@nospam.fr> wrote:
>.../...

> Merci pour vos précisions, j'y vois plus clair.

De rien.

> Seul détail, pourquoi
>
> set x un
> set y deux
> set undeux 12
> puts "$${x}${y}"
>
> renvoit $undeux et non pas 12 ?

Pour bien comprendre, on va se transformer en interpréteur Tcl en se
basant sur les douze règles (http://wfr.tcl.tk/38 qui est encore à 11
le temps de transformer la 5 bis) et analyser la ligne :

puts $${x}${y}

Selon la règle 1, on a une commande qui se termine par un retour à la
ligne.

Selon les règles 2 et 3, notre commande est composée de 2 mots, le
premier étant notre commande (puts) le reste étant les arguments de
cette commande.

Je garde "puts" et il me reste à interpréter $${x}${y}

Les règles 4, 5, 5bis et 6 ne s'appliquent pas à notre deuxième mot.

Selon la règle 7, Si un mot contient un symbole dollar («$») alors TCL
exécute une substitution de variable : le symbole dollar et les
caractères suivants seront remplacés dans le mot par la valeur d'une
variable. Mais selon la règle 10, chaque caractère est traité
exactement une seule fois par l'interprèteur TCL en tant qu'élément de
création des mots d'une commande et les substitutions ont lieu de
gauche à droite et chaque substitution est évaluée complètement avant
d'essayer d'évaluer la suivante. Si on applique tout ça à notre mot $$
{x}${y} ça donne :

Je trouve un $ en première position, selon la règle 7 alinéa 1, je
prend un ou plusieurs caractères qui peuvent être une lettre, un
chiffre, un souligné, ou des séparateurs d'espace de noms qui suivent
ce $ comme nom de variable. Dans mon cas, le deuxième caractère est un
$ donc mon nom de variable est vide {} : je ne remplace pas mon dollar
puisqu'il ne représente pas une variable :

Je garde "puts $" et il me reste à interpréter ${x}${y}

Je trouve encore un dollar en première position, suivi d'une accolade,
selon la règle 7 alinéa 3, je doit donc remplacer ${x} par sa valeur :
un

Je garde "puts $un" et il me reste à interpréter ${y}

Je trouve encore un dollar en première position, suivi d'une accolade,
selon la règle 7 alinéa 3, je doit donc remplacer ${y} par sa valeur :
deux

Je garde "puts $undeux" et il me reste rien à interpréter : ma
commande est effectué et $undeux est affiché.

CQFD

> et là il est interdit d'utiliser une deuxième couche de {} comme :
> puts "${${x}${y}}"

Oui, car selon la règle 5, aucune substitution de variable n'a lieu à
l'intérieur d'accolades.

> mais il est vrai que [set ...] fait bien le travail demandé, et mon code
> fait "plus propre".

En effet, puisque l'interpréteur rencontre un crochet, selon la règle
6, on doit traiter le contenu de ce crochet récursivement, ce qui
donne :

1) puts [set $x$y] qui devient puts [set undeux]
2) puts [set undeux] qui devient puts 12

En espérant avoir été clair.

--
David Zolli

Kroc

unread,
Dec 30, 2008, 1:24:06 PM12/30/08
to
On 30 déc, 15:21, Eric Hassold <hass...@evolane.com> wrote:
> > Une solution simple pour se protéger contre ça c'est d'utiliser le
> > plus possible [subst -nocommands ...]
>
> Que neni, helas!
>
> % set var "code inclusion perverse \$tcl_platform(os\[puts AIE!\])"
> % puts [subst -nocommand $var]

Mais c'est très fourbe cette astuce de la parenthèse !!

> Et un beau "AIE!" qui apparait a l'ecran. Bien sur, un "file delete
> -force ~" et autre [exec ...] encore plus destructeur sont possible a la
> place du [puts], mais je ne voudrais pas que quelqu'un fasse un
> copier-coller du code sans lire auparavant l'avertissement "SURTOUT NE
> PAS EXECUTER".

Ah oui, j'ai pas été assez prudent sur ce coup :^/

> Pour moi, ca s'apparente plus a un "bug" qu'a un "feature", mais
> d'autre, dans d'autres discussions passees, pensaient differemment.

Si ça c'est pas un bug, je serais assez curieux de lire quelle
justification débile on a trouvé à te répondre (et qui défend ça).
D'autant qu'aucune limitation n'est donnée dans la documentation à ce
sujet !

--
David Zolli

Kroc

unread,
Dec 30, 2008, 1:27:18 PM12/30/08
to
On 30 déc, 19:12, I wrote:
> .../...

> selon la règle 7 alinéa 3, je doit donc remplacer ${y} par sa valeur :
> .../...

A force de copicollages entre "on doit" et "je dois" ça a fini sur un
mauvais mélange, désolé. :-(

--
David Zolli

Pascal

unread,
Dec 31, 2008, 3:05:39 AM12/31/08
to
Kroc a écrit :
[...]

>
> En espérant avoir été clair.
>
> --
> David Zolli

Extrêmement clair.

Merci.

Pascal Georges.

Reply all
Reply to author
Forward
0 new messages