Pourquoi les symboles protégés en AutoLISP ne sont pas complètement protégés ?

En AutoLISP, un symbole protégé est un identifiant qui appartient au noyau fondamental du langage. L’environnement de développement tente normalement de verrouiller ces symboles pour éviter qu’une modification accidentelle ne fasse planter vos scripts ou les commandes internes d’AutoCAD.

Quels sont les symboles protégés ?

La liste des symboles protégés englobe tout ce qui est natif au langage :

  • Les valeurs booléennes : T (Vrai) et nil (Faux/Vide).

  • Les constantes mathématiques : comme pi.

  • Les opérateurs arithmétiques et logiques : +, -, *, /, =, <, >, and, or.

  • Les fonctions natives (built-in) : setq, defun, car, cdr, command, entget, mapcar, etc.

Si vous assignez une nouvelle valeur à l’un de ces symboles (par exemple (setq pi 3) ou (setq setq 10)), vous écrasez la fonction ou la constante d’origine pour toute la session AutoCAD en cours, ce qui corrompt généralement l’exécution de tous les autres scripts LISP.

Pourquoi l’interprèteur ne vous prévient-il pas ?

Si vous ne recevez aucun message d’erreur lors de l’écrasement d’un symbole protégé, c’est en raison de la configuration actuelle de votre environnement de développement.

Historiquement, le langage LISP a été conçu pour être extrêmement permissif. Il autorise volontairement le développeur à redéfinir des fonctions natives pour créer des comportements sur-mesure (méta-programmation).

Pour concilier cette flexibilité avec la sécurité, AutoCAD intègre un paramètre de gestion des symboles protégés qui comporte 4 niveaux. Si vous n’avez pas d’avertissement, c’est que votre environnement est actuellement réglé sur le niveau Transparent.

Voici les 4 comportements configurables de l’interprèteur :

  1. Transparent : Les symboles protégés sont traités comme n’importe quelle variable locale. La modification est appliquée silencieusement.

  2. Afficher un message (Print message) : La modification est appliquée, mais AutoLISP affiche un avertissement discret dans la console (ex : ; *U* WARNING: assignment to protected symbol: T).

  3. Boucle d’interruption (Prompt to enter break loop) : C’est normalement le mode par défaut dans l’éditeur. Une boîte de dialogue s’ouvre pour vous alerter de l’écrasement, met le code en pause et vous permet d’annuler ou d’entrer en mode débogage.

  4. Erreur (Error) : La modification est strictement interdite. Le script s’arrête immédiatement en renvoyant une erreur fatale.

Comment réactiver les avertissements

Si vous utilisez l’éditeur classique Visual LISP intégré à AutoCAD (commande VLIDE) :

  1. Allez dans le menu Outils (Tools) > Options de l’environnement (Environment Options) > Options générales (General Options).

  2. Dans la boîte de dialogue, repérez la section dédiée au comportement des symboles protégés.

  3. Changez le paramètre de Transparent vers Prompt to enter break loop (Boucle d’interruption).

(Note : Si vous développez avec la nouvelle extension AutoLISP pour Visual Studio Code, la détection de ces écrasements repose souvent sur le linter (analyseur de code) de l’éditeur plutôt que sur l’interprèteur en direct de la ligne de commande AutoCAD).

Redéfinir des symboles protégés (les fonctions et variables natives) en AutoLISP permet d’intercepter, de modifier ou de bloquer le comportement standard du programme sans avoir à modifier le code source des scripts existants. Cette technique, souvent appelée « hooking » ou « monkey patching », exploite la nature dynamique du LISP où un nom de fonction n’est qu’une variable pointant vers une définition.

Voici les intérêts principaux de cette manipulation, illustrés par des exemples concrets.

1. Le mode silencieux (Surcharge de comportement)

Certains scripts tiers abusent de la fonction alert, ce qui génère de multiples boîtes de dialogue qui obligent l’utilisateur à cliquer sur « OK » pour continuer. Vous pouvez redéfinir alert pour rediriger ces messages vers la ligne de commande (console) afin de rendre l’exécution totalement silencieuse.

;; 1. Sauvegarder la fonction native dans une nouvelle variable
(setq old-alert alert)

;; 2. Redéfinir la fonction alert
(defun alert (msg)
  ;; Au lieu d'une boîte de dialogue, on écrit dans la console
  (princ (strcat "\n[ALERTE REDIRIGÉE] : " msg))
  (princ) ; Sortie propre
)

Tant que cette redéfinition est active, n’importe quel autre script appelant (alert "test") n’affichera plus de pop-up, mais un simple texte en console.

2. La sécurité et le « Sandboxing » (Blocage de fonctions)

Si vous exécutez des routines AutoLISP téléchargées sur internet, elles pourraient potentiellement lancer des scripts malveillants ou modifier des fichiers système via startapp ou les fonctions vl-file-*. Vous pouvez neutraliser ces fonctions.

;; Redéfinir startapp pour bloquer son exécution et alerter l'utilisateur
(defun startapp (app file)
  (princ (strcat "\n[SÉCURITÉ] Tentative de lancement d'application bloquée : " app))
  nil ; Retourne nil pour simuler un échec de la fonction native
)

3. Le débogage et le traçage (Ajout de logs)

Lorsqu’un script complexe plante AutoCAD, il est difficile de savoir où il s’est arrêté. Vous pouvez envelopper une fonction critique (comme la création d’entités avec entmake) pour qu’elle continue de faire son travail normal, mais en écrivant silencieusement un journal de son activité.

;; Sauvegarde de la fonction native
(setq old-entmake entmake)

;; Redéfinition avec injection de code (Hooking)
(defun entmake (edata)
  ;; Ajout de notre comportement de débogage
  (princ "\n[DEBUG] Création d'une entité : ")
  (princ (cdr (assoc 0 edata))) 
  
  ;; Appel de la fonction originale avec ses vrais arguments
  (old-entmake edata)
)

4. La rétrocompatibilité (Polyfilling)

Si une nouvelle version d’AutoCAD introduit une fonction native pratique mais que vous devez déployer votre code sur des versions plus anciennes, vous pouvez vérifier si le symbole est protégé (s’il existe). S’il n’existe pas, vous le redéfinissez pour qu’il imite le comportement de la nouvelle version, rendant votre code compatible partout.

;; Si la fonction vl-string-trim n'existe pas (anciennes versions)
(if (not vl-string-trim)
  (defun vl-string-trim (char-set str)
    ;; Implémentation manuelle de la fonction de nettoyage de chaîne ici...
    (princ "\nUtilisation du polyfill pour vl-string-trim")
  )
)

:warning: Avertissement technique : Cette manipulation modifie l’espace de noms global d’AutoCAD. Si vous redéfinissez une fonction vitale (comme setq ou defun) de manière incorrecte, vous allez rendre l’environnement AutoLISP inutilisable jusqu’au redémarrage d’AutoCAD. Il est impératif de toujours sauvegarder le pointeur d’origine dans une variable globale (ex: old-func) si vous comptez appeler le comportement d’origine à l’intérieur de votre nouvelle définition, sinon vous créerez une boucle infinie.