246 lines
7.8 KiB
Python
246 lines
7.8 KiB
Python
#/usr/bin/env python
|
||
# -*- coding: utf8 -*-
|
||
|
||
def human_to_ldap(filtre):
|
||
"""
|
||
Transforme les filtres "human readables" en
|
||
filtres respectant la syntaxe LDAP.
|
||
"""
|
||
# Piles, quand on croise une parenthèse ouvrante
|
||
# on change de pile
|
||
stacks = {0:''}
|
||
|
||
# Position dans la pile
|
||
pos = 0
|
||
|
||
# operateur \in {&, |, &|, }
|
||
operateur = ""
|
||
|
||
# La pile externe, qu'on merge à la pile en cours quand c'est utile.
|
||
ext_stack = ""
|
||
|
||
# Élement de la forme paiement=2012 ou retour de la pile
|
||
# supérieure (quand on croise une parenthèse fermante, la
|
||
# pile est dumpée dans argument)
|
||
# Est systématiquement dumpé dans ext_stack quand on croise
|
||
# un opérateur.
|
||
argument = ""
|
||
|
||
# Y a-t-il un ! dans la salle ?
|
||
neg = False
|
||
|
||
# Quand on quitte une pile parenthésée, on veut savoir quel était
|
||
# l'opérateur actif avant, pour que le comportement de la fonction
|
||
# soit défini.
|
||
anciens_operateurs = []
|
||
|
||
for char in filtre:
|
||
if char == "(":
|
||
|
||
# Une nouvelle stack ne démarre que si le dernier argument a été dumpé
|
||
# dans l'ext stack (si ce n'est pas le cas quand on respecte la syntaxe
|
||
# des filtres, la fonction est mal codée, donc on plante).
|
||
if argument != "":
|
||
raise ValueError('Argument entammé non terminé !')
|
||
|
||
# Un dumpe ext_stack dans la stack en cours.
|
||
stacks[pos] += "%s" % (ext_stack)
|
||
|
||
# On augmente le conteur de la stack
|
||
pos = pos + 1
|
||
|
||
# On (ré)?initialise la stack
|
||
stacks[pos] = ''
|
||
|
||
# On stocke l'opérateur en cours dans la stack inférieure dans
|
||
# une liste.
|
||
anciens_operateurs.append(operateur)
|
||
|
||
# On flush operateur
|
||
operateur = ""
|
||
|
||
# On flush ext_stack, l'environnement est enfin propre pour
|
||
# bosser dans la nouvelle pile.
|
||
ext_stack = ""
|
||
|
||
elif char == ")":
|
||
# Cas classique
|
||
if operateur == "|":
|
||
ext_stack += "(%s)" % argument
|
||
|
||
# Moins classique, &| est un opérateur servant à dire qu'on
|
||
# a déjà croisé un | dans la stack en cours, le cas échéant,
|
||
# celui-ci doit être pris en compte, pour respecter la
|
||
# priorité du &. Dans ce cas seulement, une parenthèse
|
||
# est ouverte et non fermée (cf elif char == '&' cas
|
||
# operateur == "|"), on la ferme ici.
|
||
elif operateur == "&|":
|
||
argument += ")"
|
||
ext_stack += "(%s)" % argument
|
||
|
||
# Classique
|
||
elif operateur == "&":
|
||
ext_stack += "(%s)" % argument
|
||
|
||
# Pas d'opérateur, pas de parenthèse superflue.
|
||
else:
|
||
ext_stack += "%s" % argument
|
||
|
||
# On passe la stack en argument, les parenthèses
|
||
# l'encadrant seront placées d'un qu'un opérateur
|
||
# sera croisé.
|
||
argument = "%s%s" % (stacks[pos], ext_stack)
|
||
|
||
# Ménage
|
||
stacks[pos] = ""
|
||
ext_stack = ""
|
||
pos = pos - 1
|
||
|
||
# Retour à l'opérateur de la stack précédente.
|
||
operateur = anciens_operateurs.pop()
|
||
|
||
elif char == "|":
|
||
if not argument:
|
||
raise ValueError('Aucun argument')
|
||
|
||
# Ce cas permet d'éviter une répétition de la forme :
|
||
# (|(a)(|(b)(c))), quand on est déjà dans un ou, on
|
||
# rajoute juste l'argument suivant sans remettre de
|
||
# symbole.
|
||
if operateur == "|":
|
||
# neg est True si on a croisé un ! dans la chaîne.
|
||
# À améliorer pour qu'il ne marche que pour !=
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
# Ajout à la stack externe de l'argument
|
||
ext_stack += "(%s)" % argument
|
||
argument = ""
|
||
|
||
elif operateur == "&":
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
ext_stack += "(%s)" % argument
|
||
|
||
# | prend le relais sur &, on dumpe ext_stack et on commence une nouvelle
|
||
# chaîne qui sera ajoutée à droite. Le ou va tout à gauche de la stack
|
||
# en cours, pour s'appliquer sur tout son contenu.
|
||
stacks[pos] = "%s(%s%s)" % (char, stacks[pos], ext_stack)
|
||
ext_stack = ""
|
||
argument = ""
|
||
operateur = "|"
|
||
|
||
# C'est un & dans un |, donc on ferme juste la chaîne
|
||
# des &, d'où la parenthèse fermante en trop.
|
||
elif operateur == "&|":
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
ext_stack += "(%s)" % argument
|
||
argument = ""
|
||
stacks[pos] = "%s%s)" % (stacks[pos], ext_stack)
|
||
ext_stack = ""
|
||
operateur = "|"
|
||
|
||
# Pas encore d'opérateur annoncé
|
||
elif operateur == "":
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
ext_stack += "%s" % argument
|
||
argument = ""
|
||
|
||
# ouverture
|
||
stacks[pos] = "%s(%s%s)" % (char, stacks[pos], ext_stack)
|
||
ext_stack = ""
|
||
operateur = "|"
|
||
|
||
else:
|
||
raise TypeError('Erreur d\'opérateur.')
|
||
|
||
elif char == "&":
|
||
if not argument:
|
||
raise ValueError('Aucun argument')
|
||
|
||
if operateur == "&":
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
ext_stack += "(%s)" % argument
|
||
argument = ""
|
||
|
||
# Le cas spécial, on ouvre un & après un |, donc pour respecter
|
||
# la priorité de &, on démarre une nouvelle chaîne, mais dans
|
||
# l'ext_stack (contrairement à char == '|', operateur == "&")
|
||
elif operateur == "|":
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
ext_stack += "(%s(%s)" % (char, argument)
|
||
argument = ""
|
||
operateur = "&|"
|
||
|
||
# On était déjà dans un &|...
|
||
elif operateur == "&|":
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
ext_stack += "(%s)" % argument
|
||
argument = ""
|
||
|
||
# Comme ci-dessus
|
||
elif operateur == "":
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
neg = False
|
||
|
||
ext_stack += "%s" % argument
|
||
argument = ""
|
||
|
||
stacks[pos] = "%s(%s%s)" % (char, stacks[pos], ext_stack)
|
||
ext_stack = ""
|
||
operateur = "&"
|
||
|
||
else:
|
||
raise TypeError('Erreur d\'opérateur.')
|
||
|
||
elif char == "!":
|
||
neg = True
|
||
|
||
# Remplissage d'argument
|
||
else:
|
||
argument += char
|
||
|
||
# Décommenter pour débug.
|
||
# En modifiant un peu, encore plus utile pour savoir ce qu'il
|
||
# fait à chaque étape !
|
||
#print stacks
|
||
#print pos, argument, ext_stack, operateur
|
||
|
||
if pos > 0:
|
||
raise Exception("Tu ne sais pas parenthéser, crétin.")
|
||
|
||
else:
|
||
# Comme parenthèse fermante.
|
||
if neg:
|
||
argument = "!(%s)" % argument
|
||
|
||
# Surtout ça
|
||
if operateur == "&|":
|
||
argument += ')'
|
||
ext_stack += "(%s)" % argument
|
||
|
||
argument = ""
|
||
stacks[pos] = "(%s%s)" % (stacks[pos], ext_stack)
|
||
ext_stack = ""
|
||
|
||
# On retourne la pile de plus haut niveau
|
||
return stacks[0]
|