Utilisation d'inifile

From Base de connaissances eggdrops & TCL
Jump to: navigation, search

Beaucoup de personnes utilisent dans leurs tcl des fichiers de configuration en tcl alors qu'un fichier d'initialisation peut parfois faire l'affaire et est très bien géré.

Attention.png Le package inifile n'est inclus dans tcllib qu'à partir de la version 1.6

Inifile ?

Ce type de fichier est un standard qui vient de windows. Il contient un ensemble de sections, qui contiennent des paires clé=valeur et des commentaires.

Exemple de fichier

; The comment of section 1
; Another comment of section 1

[section1]
; The comment of section 1 - key 1
key1=value1
key2=value2

; The comment of section 2

[section2]
key1=value1
; The comment of section 2 - key 2
key2=value2

Explications

Une même clé peut être présente dans différentes sections

Le tout premier point à savoir est qu'un commentaire se place avant l'élement qu'il commente, et qu'il s'agit d'une (ou plusieurs) ligne(s) de texte démarrant par le caractère de commentaire (par défaut ";").

Les sections sont simplement reconnaissables, elles sont encadrées par des crochets. Tout élément (hormis les commentaires de sections) doit se trouver dans une section.

Les ensembles Clé/Valeur sont de simples lignes de la forme clé=valeur.

A priori, rien ne vous empèche d'utiliser des noms de section et de clés étranges, c'est à dire avec des espaces ou des caractères spéciaux, mais c'est fortement déconseillé car cela peut causer des soucis lors de leur utilisation en tcl.

Création d'un fichier

Notes sur l'ouverture

  • Ainsi qu'il est bien précisé sur la page Inifile, l'ouverture par défaut d'un fichier .ini se fait en mode "r+" (lecture avec possibilité d'écriture), ce qui fait qu'une erreur se produit si vous tentez d'ouvrir un fichier absent.
  • Le mode "a" (append, écrire à la suite) n'existe pas.
  • Si vous ouvrez un fichier .ini en mode "w+", il estautomatiquement vidé.

Ces trois points font que je (notez bien que c'est un avis personnel) préfère passer par une étape de vérification de la présence du fichier et création si nécessaire plutôt que d'ouvrir aveuglément le fichier.

Script de création

Voici le script qui m'a permis de créer le fichier exemple présenté ci-dessus:

package require inifile

bind dcc - ini inifile:ini

set myini "databases/test.ini"

proc inifile:ini {handle idx text} {
	if {![file exists $::myini] } {
		inifile:create
	}
	set ini [::ini::open $::myini]
	::ini::set $ini "section1" "key1" "value1"
	::ini::set $ini "section1" "key2" "value2"
	::ini::set $ini "section2" "key1" "value1"
	::ini::set $ini "section2" "key2" "value2"
	::ini::comment $ini "section1" "" "The comment of section 1"
	::ini::comment $ini "section1" "" "Another comment of section 1"
	::ini::comment $ini "section1" "key1" "The comment of section 1 - key 1"
	::ini::comment $ini "section2" "" "The comment of section 2"
	::ini::comment $ini "section2" "key2" "The comment of section 2 - key 2"
	::ini::commit $ini
	::ini::close $ini
}

proc inifile:create {} {
	set fo [open $::myini "w"]
	puts $fo ";initialised"
	close $fo
	return 1
}

Explications

  • Vous pouvez constater que le commentaire créé par la procédure inifile:create n'est pas présent dans le fichier généré. Tout simplement parce que lorsqu'il a été édité ensuite par les commandes ::ini, ce commentaire n'était rattaché à rien, il a donc été supprimé.
  • La structure des commandes ::ini::set et ::ini::comment est telle qu'un élément (clé/valeur ou commentaire) dépend obligatoirement d'une section. Les sections sont créées automatiquement.
  • L'appel à ::ini::commit est le seul moyen de sauvegarder votre fichier. Tant que cet appel n'est pas fait, votre fichier ne sera pas modifié.

Lecture d'un fichier

Ceci est la partie qui est certainement la plus importante et la plus utile, car le fichier sert essentiellement à l'initialisation des données. C'est aussi la chose la plus simple à réaliser.

Lorsque le fichier est ouvert, vous avez essentiellement accès à une chose: la liste des sections présentes. Celle-ci est accessible avec la commande ::ini::sections $ini. Et une seconde commande fort utile est la vérification de la présence d'une section avec ::ini::exists $ini "section".

Imaginons un fichier .ini qui contient des configurations de réglage d'un script pour les canaux, avec une section default qui sera les réglages par défaut, et deux sections spécifiques: canal1 pour #canal1 et canal2 pour #canal2. Et bien entendu, notre script chargera automatiquement la configuration du canal lorsqu'il le rejoindra.

Fichier config.ini

Ce fichier établit des règles par défaut (qui doivent être complètes) et des règles spécifiques. Il a été écrit à la main, donc les sections (autres que "default") ne comprennent que les modifications.

[default]
; Limite de phrases par secondes
: pour détexter un flood
flood=10:6
; Topic du canal
topic=Topic par défaut
; modes du canal
modes=t,n

[canal1]
flood=0:0
topic=Bienvenue sur le canal 1

[canal2]
modes=t,n,R

Script de chargement

Le script va être pour l'instant assez simple: chaque fois que l'eggdrop rejoint un canal, il applique les règles du canal, ou celles par défaut si elles ne sont pas spécifiées:

set myconf "databases/config.ini"

bind join - * load:conf
proc load:conf {nick uhost handle chan} {
   if { [string tolower $nick] != [string tolower $::botnick] } { return 0; }
   set ichan [string range $chan 1 end]
   set ini [::ini::open $::myconf]
   variable settings
   array set settings [::ini::get $ini "default"]
   if { [::ini::exists $ini $ichan] } {
      array set setting [::ini:get $ini $ichan]
   }
   ::ini::close $ini
}

Explications

Ce code très simple charge dans le tableau $settings le contenu de la section default, et si une section correspondant au nom du canal rejoint existe, il remplace les entrées existantes par celles de la section. Notez que si nous avions affecté des clés n'existant pas dans default, elles auraient aussi été ajoutées, nous procédons à un merge de tableaux.

A présent, le tableau $settings est de la forme, si l'eggdrop a rejoint le canal #canal2: settings(flood) "10:6" settings(topic) "Topic par défaut" settings(modes) "t,n,R"

Un peu plus loin

Si nous voulons pouvoir interroger l'eggdrop sur les canaux configurés et les options présentes, nous pouvons ajouter la partie de code suivante:

bind msg n "!confs" info:conf
proc info:conf { nick uhost handle chan args} {
   set ini [::ini::open $::myconf]
   if { [llength $args] == 0] } {
      putserv "PRIVMSG $nick :Liste des canaux configurés:"
      putserv "PRIVMSG $nick :[join [::ini::sections $ini]]"
   } else {
      set ichan [string range [lindex $args 0] 1 end]
      if { ![::ini::exists $ini $ichan] } {
         putserv "PRIVMSG $nick :Le canal #$ichan n'est pas configuré"
      } else {
         putserv "PRIVMSG $nick :Le canal #$ichan a des réglages pour [join [::ini::keys $ini $ichan]]"
      }
   }
}

Dans l'état, cette commande nous renverra, si on l'interroge pour #canal2, "Le canal #canal2 a des réglages pour modes". Ce qui est juste si on regarde le fichier .ini, mais faux si l'on relit le script. D'ailleurs, si nous faisons rejoindre #canal3 à l'egddrop, il aura les paramètres par défaut mais répondra à la commande: "Le canal #canal3 n'est pas configuré".

Nous allons donc modifier la procédure load:conf pour sauvegarder automatiquement les informations.

proc load:conf {nick uhost handle chan} {
   if { [string tolower $nick] != [string tolower $::botnick] } { return 0; }
   set ichan [string range $chan 1 end]
   set ini [::ini::open $::myconf]
   variable settings
   array set settings [::ini::get $ini "default"]
   if { [::ini::exists $ini $ichan] } {
      array set settings [::ini:get $ini $ichan]
   }
   # Début de modification
   foreach key [array names $settings] {
      ::ini::set $ini $ichan $key $settings($key)
   }
   ::ini::commit $ini
   # Fin de modification
   ::ini::close $ini
}

Avec cette modification de moins de 5 lignes, la section correspondant au canal rejoint est remis à jour dans le fichier .ini.

Conclusion

Cette brève explication sur l'utilisation des fichiers d'initialisation permet de démontrer la simplicité d'utilisation, que ce soit en lecture ou en maintenance, de ses fichiers. Ils sont très pratique pour gérer des données simples de configuration, et n'ont en aucun cas pour vocation de remplacer des fichiers de données.

Voir aussi

Inifile, Discussion "Fichiers .ini en tcl"

Liens externes