Parcours d’arborescence en TinyScheme pour Gimp

18 08 2010

Dans le cadre d’une macro Gimp Script-Fu de traitement par lot, vous pourriez avoir besoin de parcourir toute une arborescence et pas seulement un répertoire à la recherche de fichier de types précis. La fonction file-glob permet de le faire mais seulement sur un seul niveau.

Voici la fonction parcours-repertoires qui permet de combler ce manque.

Utilisation

Pour fonctionner, il vous faut les fonctions suivantes :

Les fonctions est-un-repertoire? et est-un-fichier? sont des fonctions créées pour simplifier l’écriture (la lecture ?) de la fonction parcours-repertoires.

La fonction parcours-repertoires s’utilise de la façon suivante :

(parcours-repertoires <répertoire> <profondeur max> <liste des extensions recherchées>)

Les paramètres sont les suivants :

  • répertoire : le répertoire de départ, sans slash ou anti-slash terminal (“/home/utilisateur” est valide mais pas “/home/utilisateur/”),
  • profondeur max : niveau de profondeur maximum de recherche dans l’arborescence, un niveau à 1 ne recherche que dans le répertoire donné et pas dans ses sous-répertoires, un niveau à 2 recherche dans le répertoire donné, dans ses sous-répertoires directs mais pas dans les sous-répertoires des sous-répertoires etc. Indiquer une grande valeur pour aller au bout de l’arborescence (16 est un bon candidat)
  • liste des extensions recherchées : une liste de chaînes de caractères contenant des extensions sous la forme “.png” “.jpeg” (le point est important et la fonction ne comprend pas les caractères génériques * ou ?) ; note : pensez à mettre les variantes avec des majuscules ex. : “.jpg” “.JPG” “.jpeg” “.JPEG” “.Jpeg” etc.

La fonction parcours-repertoires retourne une liste de tous les fichiers répondant aux critères donnés dans les paramètres. Chaque chaîne contenue dans cette liste est un chemin vers le fichier incluant le répertoire (un chemin absolu si le répertoire fourni est lui-même absolu).

La fonction a été développée sous Linux mais elle devrait également fonctionner sous Windows (mais cela n’a pas été testé !).

Exemple d’appel :

(parcours-repertoires « /home/utilisateur » 16 (list « .png » « .jpg » « .gif »))

Code source

; Teste si une valeur se trouve dans une liste
(define (est-dans? valeur liste)
  (cond
    ; Si la liste est nulle, la valeur ne peut pas s’y trouver
    ((null? liste) #f)

    ; Si le premier élément de la liste est égale à la valeur on retourne vrai
    ((equal? valeur (car liste)) #t)

    ; Sinon on recherche la valeur dans le reste de la liste
    (else (est-dans? valeur (cdr liste)))
  )
)

; Retourne un nom de fichier sans son extension
(define (sans-extension nom-fichier)
  (let loop ((nom nom-fichier))
    (cond
      ; Si le nom est vide, il n’y a pas d’extension, on retourne le nom complet
      ((string=? nom "") nom-fichier)

      ; Si le dernier caractère est un séparateur de répertoire
      ((string=? (substring nom (- (string-length nom) 1) (string-length nom)) DIR-SEPARATOR)
        ; on retourne le nom complet
        nom-fichier
      )

      ; Si le dernier caractère est un point
      ((char=? (string-ref nom (- (string-length nom) 1)) #\.)
        ; on retourne le nom en lui enlevant le dernier caractère
        (substring nom 0 (- (string-length nom) 1))
      )

      ; Sinon on supprime le dernier caractère du nom et on boucle
      (else (loop (substring nom 0 (- (string-length nom) 1))))
    )
  )
)

; Retourne l’extension d’un nom de fichier
(define (extension nom-fichier)
  ; Extension=nom de fichier - nom de fichier sans extension
  (substring nom-fichier (string-length (sans-extension nom-fichier)))
)

; Vérifie si un chemin est un répertoire
(define (est-un-repertoire? repertoire entree)
  (=
    (file-type (string-append repertoire DIR-SEPARATOR entree))
    FILE-TYPE-DIR
  )
)

; Vérifie si un chemin est un fichier standard
(define (est-un-fichier? repertoire entree)
  (=
    (file-type (string-append repertoire DIR-SEPARATOR entree))
    FILE-TYPE-FILE
  )
)

; Retourne la liste de tous les fichiers des répertoires et sous-répertoires
(define (parcours-repertoires repertoire niveau extensions)
  (let*
    (
      ; Récupère un curseur sur le contenu du répertoire
      (stream (dir-open-stream repertoire))

      ; Récupère la liste des fichiers
      (retour
        ; Boucle sur la liste des fichiers du répertoire
        (let loop ((entree (dir-read-entry stream)) (entrees '()))
          (cond
            ; Si on est arrivé en fin de liste, on retourne la liste des
            ; fichiers trouvés
            ((or (eof-object? entree) (equal? entree #f)) entrees)

            ; Si l’entrée est un répertoire et que le niveau le permet,
            ; on récupère la liste de ses fichiers par récursivité et on
            ; l’ajoute à la liste en cours
            ((and (est-un-repertoire? repertoire entree)
                  (> niveau 1))
              (loop
                (dir-read-entry stream)
                (append
                  entrees
                  (parcours-repertoires
                    (string-append repertoire DIR-SEPARATOR entree)
                    (- niveau 1)
                    extensions
                  )
                )
              )
            )

            ; Si l’entrée est un fichier et que son extension est dans la liste
            ; des extensions autorisées, on ajoute l’entrée à la liste en cours
            ; et on passe à l’entrée suivante
            ((and (est-un-fichier? repertoire entree)
                  (est-dans? (extension entree) extensions))
              (loop
                (dir-read-entry stream)
                (cons (string-append repertoire DIR-SEPARATOR entree) entrees)
              )
            )

            ; Sinon on passe à l’entrée suivante
            (else (loop (dir-read-entry stream) entrees))
          )
        )
      )
    )

    ; Ferme le curseur sur le répertoire
    (dir-close-stream stream)

    ; Retourne la liste des fichiers trouvés
    retour
  )
)

Fonctionnement

La fonction parcours-repertoires fait appel aux fonctions dir-open-stream, dir-read-entry et dir-close-stream pour parcourir l’arborescence. Elle ne fait pas appel à la fonction file-glob. En plus du désavantage de ne pouvoir parcourir une arborescence en profondeur, elle n’est pas capable de rechercher plusieurs extensions à la fois.

Concernant l’utilisation de la fonction dir-read-entry, j’ai ajouté le test (equal? entree #f) car il lui arrive de retourner #f en lieu et place de #<EOF>. Je ne sais pas pourquoi ! Est-ce une mauvaise utilisation de ma part ? Un bug dans dir-read-entry ? Ou un fonctionnement que je n’aurais pas saisi ? Si quelqu’un a la réponse, je suis preneur !


Actions

Information

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s




%d blogueurs aiment cette page :