Commit | Line | Data |
---|---|---|
c495c100 P |
1 | <?php |
2 | ||
3 | /***************************************************************************\ | |
4 | * SPIP, Systeme de publication pour l'internet * | |
5 | * * | |
6 | * Copyright (c) 2001-2007 * | |
7 | * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * | |
8 | * * | |
9 | * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * | |
10 | * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * | |
11 | \***************************************************************************/ | |
12 | ||
13 | ||
14 | if (!defined("_ECRIRE_INC_VERSION")) return; | |
15 | ||
16 | # Ce fichier doit IMPERATIVEMENT definir la fonction "public_phraser_html" | |
17 | # qui transforme un squelette en un tableau d'objets de classe Boucle | |
18 | # il est charge par un include calcule dans inc-calcul-squel | |
19 | # pour permettre differentes syntaxes en entree | |
20 | ||
21 | define('BALISE_BOUCLE', '<BOUCLE'); | |
22 | define('BALISE_FIN_BOUCLE', '</BOUCLE'); | |
23 | define('BALISE_PRE_BOUCLE', '<B'); | |
24 | define('BALISE_POST_BOUCLE', '</B'); | |
25 | define('BALISE_ALT_BOUCLE', '<//B'); | |
26 | ||
27 | define('TYPE_RECURSIF', 'boucle'); | |
28 | define('SPEC_BOUCLE','/\s*\(\s*([^\s)]+)(\s*[^)]*)\)/'); | |
29 | define('NOM_DE_BOUCLE', "[0-9]+|[-_][-_.a-zA-Z0-9]*"); | |
30 | # ecriture alambiquee pour rester compatible avec les hexadecimaux des vieux squelettes | |
31 | define('NOM_DE_CHAMP', "#((" . NOM_DE_BOUCLE . "):)?(([A-F]*[G-Z_][A-Z_0-9]*)|[A-Z_]+)(\*{0,2})"); | |
32 | define('CHAMP_ETENDU', '\[([^]\[]*)\(' . NOM_DE_CHAMP . '([^[)]*\)[^]\[]*)\]'); | |
33 | ||
34 | define('BALISE_INCLURE','<INCLU[DR]E[[:space:]]*(\(([^)]*)\))?'); | |
35 | ||
36 | define('SQL_ARGS', '(\([^)]*\))'); | |
37 | define('CHAMP_SQL_PLUS_FONC', '`?([A-Z_][A-Z_0-9]*)' . SQL_ARGS . '?`?'); | |
38 | ||
39 | // http://doc.spip.org/@phraser_arguments_inclure | |
40 | function phraser_arguments_inclure($p,$rejet_filtres = false){ | |
41 | $champ = new Inclure; | |
42 | // on assimile {var=val} a une liste de un argument sans fonction | |
43 | foreach ($p->param as $k => $v) { | |
44 | $var = $v[1][0]; | |
45 | if ($var==NULL){ | |
46 | if ($rejet_filtres) | |
47 | break; // on est arrive sur un filtre sans argument qui suit la balise | |
48 | else | |
49 | $champ->param[$k] = $v; | |
50 | } | |
51 | else { | |
52 | if ($var->type != 'texte') | |
53 | if ($rejet_filtres) | |
54 | break; // on est arrive sur un filtre sans argument qui suit la balise | |
55 | else | |
56 | erreur_squelette(_T('zbug_parametres_inclus_incorrects'),$var); | |
57 | else { | |
58 | $champ->param[$k] = $v; | |
59 | ereg("^([^=]*)(=)?(.*)$", $var->texte,$m); | |
60 | if ($m[2]) { | |
61 | $champ->param[$k][0] = $m[1]; | |
62 | $val = $m[3]; | |
63 | if (ereg('^[\'"](.*)[\'"]$', $val, $m)) $val = $m[1]; | |
64 | $champ->param[$k][1][0]->texte = $val; | |
65 | } | |
66 | else | |
67 | $champ->param[$k] = array($m[1]); | |
68 | } | |
69 | } | |
70 | } | |
71 | return $champ; | |
72 | } | |
73 | ||
74 | // http://doc.spip.org/@phraser_inclure | |
75 | function phraser_inclure($texte, $ligne, $result) { | |
76 | ||
77 | while (ereg(BALISE_INCLURE, $texte, $match)) { | |
78 | $p = strpos($texte,$match[0]); | |
79 | $debut = substr($texte, 0, $p); | |
80 | if ($p) $result = phraser_idiomes($debut, $ligne, $result); | |
81 | $ligne += substr_count($debut, "\n"); | |
82 | $champ = new Inclure; | |
83 | $champ->ligne = $ligne; | |
84 | $ligne += substr_count($match[0], "\n"); | |
85 | $champ->texte = $match[2]; | |
86 | $texte = substr($texte, $p+strlen($match[0])); | |
87 | // on assimile {var=val} a une liste de un argument sans fonction | |
88 | phraser_args($texte,">","",$result,$champ); | |
89 | $champ_ = phraser_arguments_inclure($champ); | |
90 | $champ->param = $champ_->param; | |
91 | $texte = substr($champ->apres,1); | |
92 | $champ->apres = ""; | |
93 | if (preg_match(',^</INCLU[DR]E>,', $texte)) { | |
94 | $texte = substr($texte,10); | |
95 | } | |
96 | $result[] = $champ; | |
97 | } | |
98 | return (($texte==="") ? $result : phraser_idiomes($texte, $ligne, $result)); | |
99 | } | |
100 | ||
101 | // http://doc.spip.org/@phraser_polyglotte | |
102 | function phraser_polyglotte($texte,$ligne, $result) { | |
103 | ||
104 | if (preg_match_all(",<multi>(.*)</multi>,Uims", $texte, $m, PREG_SET_ORDER)) | |
105 | foreach ($m as $match) { | |
106 | $p = strpos($texte, $match[0]); | |
107 | $debut = substr($texte, 0, $p); | |
108 | if ($p) { | |
109 | $champ = new Texte; | |
110 | $champ->texte = $debut; | |
111 | $champ->ligne = $ligne; | |
112 | $result[] = $champ; | |
113 | $ligne += substr_count($champ->texte, "\n"); | |
114 | } | |
115 | ||
116 | $champ = new Polyglotte; | |
117 | $champ->ligne = $ligne; | |
118 | $ligne += substr_count($match[0], "\n"); | |
119 | $lang = ''; | |
120 | $bloc = $match[1]; | |
121 | $texte = substr($texte,$p+strlen($match[0])); | |
122 | while (preg_match("/^[[:space:]]*([^[{]*)[[:space:]]*[[{]([a-z_]+)[]}](.*)$/si", $bloc, $regs)) { | |
123 | $trad = $regs[1]; | |
124 | if ($trad OR $lang) | |
125 | $champ->traductions[$lang] = $trad; | |
126 | $lang = $regs[2]; | |
127 | $bloc = $regs[3]; | |
128 | } | |
129 | $champ->traductions[$lang] = $bloc; | |
130 | $result[] = $champ; | |
131 | } | |
132 | if ($texte!=="") { | |
133 | $champ = new Texte; | |
134 | $champ->texte = $texte; | |
135 | $champ->ligne = $ligne; | |
136 | $result[] = $champ; | |
137 | } | |
138 | return $result; | |
139 | } | |
140 | ||
141 | ||
142 | // http://doc.spip.org/@phraser_idiomes | |
143 | function phraser_idiomes($texte,$ligne,$result) { | |
144 | ||
145 | // Reperer les balises de traduction <:toto:> | |
146 | while (eregi("<:(([a-z0-9_]+):)?([a-z0-9_]+)((\|[^:>]*)?:>)", $texte, $match)) { | |
147 | $p = strpos($texte, $match[0]); | |
148 | $debut = substr($texte, 0, $p); | |
149 | if ($p) $result = phraser_champs($debut, $ligne, $result); | |
150 | $champ = new Idiome; | |
151 | $ligne += substr_count($debut, "\n"); | |
152 | $champ->ligne = $ligne; | |
153 | $ligne += substr_count($match[0], "\n"); | |
154 | $texte = substr($texte,$p+strlen($match[0])); | |
155 | $champ->nom_champ = strtolower($match[3]); | |
156 | $champ->module = $match[2] ? $match[2] : 'public/spip/ecrire'; | |
157 | // pas d'imbrication pour les filtres sur langue | |
158 | phraser_args($match[5], ":", '', array(), $champ); | |
159 | $result[] = $champ; | |
160 | } | |
161 | if ($texte!=="") $result = phraser_champs($texte,$ligne,$result); | |
162 | return $result; | |
163 | } | |
164 | ||
165 | // http://doc.spip.org/@phraser_champs | |
166 | function phraser_champs($texte,$ligne,$result) { | |
167 | while (ereg(NOM_DE_CHAMP, $texte, $match)) { | |
168 | $p = strpos($texte, $match[0]); | |
169 | $suite = substr($texte,$p+strlen($match[0])); | |
170 | if ($match[5] || (strpos($suite[0], "[0-9]") === false)) { | |
171 | $debut = substr($texte, 0, $p); | |
172 | if ($p) $result = phraser_polyglotte($debut, $ligne, $result); | |
173 | $ligne += substr_count($debut, "\n"); | |
174 | $champ = new Champ; | |
175 | $champ->ligne = $ligne; | |
176 | $ligne += substr_count($match[0], "\n"); | |
177 | $champ->nom_boucle = $match[2]; | |
178 | $champ->nom_champ = $match[3]; | |
179 | $champ->etoile = $match[5]; | |
180 | if ($suite[0] == '{') { | |
181 | phraser_arg($suite, '', array(), $champ); | |
182 | } | |
183 | $texte = $suite; | |
184 | $result[] = $champ; | |
185 | } else { | |
186 | // faux champ | |
187 | $result = phraser_polyglotte (substr($texte, 0, $p+1), $ligne, $result); | |
188 | $texte = (substr($texte, $p+1)); | |
189 | } | |
190 | } | |
191 | if ($texte!=="") $result = phraser_polyglotte($texte, $ligne, $result); | |
192 | return $result; | |
193 | } | |
194 | ||
195 | // Gestion des imbrications: | |
196 | // on cherche les [..] les plus internes et on les remplace par une chaine | |
197 | // %###N@ ou N indexe un tableau comportant le resultat de leur analyse | |
198 | // on recommence tant qu'il y a des [...] en substituant a l'appel suivant | |
199 | ||
200 | // http://doc.spip.org/@phraser_champs_etendus | |
201 | function phraser_champs_etendus($texte, $ligne,$result) { | |
202 | if ($texte==="") return $result; | |
203 | $sep = '##'; | |
204 | while (strpos($texte,$sep)!== false) | |
205 | $sep .= '#'; | |
206 | return array_merge($result, phraser_champs_interieurs($texte, $ligne, $sep, array())); | |
207 | } | |
208 | ||
209 | // Analyse les filtres d'un champ etendu et affecte le resultat | |
210 | // renvoie la liste des lexemes d'origine augmentee | |
211 | // de ceux trouves dans les arguments des filtres (rare) | |
212 | // sert aussi aux arguments des includes et aux criteres de boucles | |
213 | // Tres chevelu | |
214 | ||
215 | // http://doc.spip.org/@phraser_args | |
216 | function phraser_args($texte, $fin, $sep, $result, &$pointeur_champ) { | |
217 | $texte = ltrim($texte); | |
218 | while (($texte!=="") && strpos($fin, $texte[0]) === false) { | |
219 | $result = phraser_arg($texte, $sep, $result, $pointeur_champ); | |
220 | } | |
221 | # mettre ici la suite du texte, | |
222 | # notamment pour que l'appelant vire le caractere fermant si besoin | |
223 | $pointeur_champ->apres = $texte; | |
224 | return $result; | |
225 | } | |
226 | ||
227 | // http://doc.spip.org/@phraser_arg | |
228 | function phraser_arg(&$texte, $sep, $result, &$pointeur_champ) { | |
229 | preg_match(",^(\|?[^}{)|]*)(.*)$,ms", $texte, $match); | |
230 | $suite = ltrim($match[2]); | |
231 | $fonc = trim($match[1]); | |
232 | if ($fonc && $fonc[0] == "|") $fonc = ltrim(substr($fonc,1)); | |
233 | $res = array($fonc); | |
234 | $args = $suite ; | |
235 | // cas du filtre sans argument ou du critere / | |
236 | if (($suite[0] != '{') || ($fonc && $fonc[0] == '/')) | |
237 | { | |
238 | // si pas d'argument, alors il faut une fonction ou un double | | |
239 | if (!$match[1]) | |
240 | erreur_squelette(_T('zbug_info_erreur_squelette'), $texte); | |
241 | } else { | |
242 | $args = ltrim(substr($suite,1)); | |
243 | $collecte = array(); | |
244 | while ($args && $args[0] != '}') { | |
245 | if ($args[0] == '"') | |
246 | preg_match ('/^(")([^"]*)(")(.*)$/ms', $args, $regs); | |
247 | else if ($args[0] == "'") | |
248 | preg_match ("/^(')([^']*)(')(.*)$/ms", $args, $regs); | |
249 | else { | |
250 | preg_match("/^([[:space:]]*)([^,([{}]*([(\[{][^])}]*[])}])?[^,}]*)([,}].*)$/ms", $args, $regs); | |
251 | if (!strlen($regs[2])) | |
252 | { | |
253 | erreur_squelette(_T('zbug_info_erreur_squelette'), $args); | |
254 | $args = ''; | |
255 | exit; | |
256 | } | |
257 | } | |
258 | $arg = $regs[2]; | |
259 | ||
260 | if (trim($regs[1])) { | |
261 | $champ = new Texte; | |
262 | $champ->texte = $arg; | |
263 | $champ->apres = $champ->avant = $regs[1]; | |
264 | $result[] = $champ; | |
265 | $collecte[] = $champ; | |
266 | $args = ltrim($regs[count($regs)-1]); | |
267 | } else { | |
268 | if (!ereg(NOM_DE_CHAMP ."[{|]", $arg, $r)) { | |
269 | // 0 est un aveu d'impuissance. A completer | |
270 | $arg = phraser_champs_exterieurs($arg, 0, $sep, $result); | |
271 | ||
272 | $args = ltrim($regs[count($regs)-1]); | |
273 | $collecte = array_merge($collecte, $arg); | |
274 | $result = array_merge($result, $arg); | |
275 | } | |
276 | else { | |
277 | $n = strpos($args,$r[0]); | |
278 | $pred = substr($args, 0, $n); | |
279 | $par = ',}'; | |
280 | if (ereg('^(.*)\($', $pred, $m)) | |
281 | {$pred = $m[1]; $par =')';} | |
282 | if ($pred) { | |
283 | $champ = new Texte; | |
284 | $champ->texte = $pred; | |
285 | $champ->apres = $champ->avant = ""; | |
286 | $result[] = $champ; | |
287 | $collecte[] = $champ; | |
288 | } | |
289 | $rec = substr($args, $n + strlen($r[0]) -1); | |
290 | $champ = new Champ; | |
291 | $champ->nom_boucle = $r[2]; | |
292 | $champ->nom_champ = $r[3]; | |
293 | $champ->etoile = $r[5]; | |
294 | phraser_args($rec, $par, $sep, array(), $champ); | |
295 | $args = $champ->apres ; | |
296 | $champ->apres = ''; | |
297 | if ($par==')') $args = substr($args,1); | |
298 | $collecte[] = $champ; | |
299 | $result[] = $champ; | |
300 | } | |
301 | } | |
302 | if ($args[0] == ',') { | |
303 | $args = ltrim(substr($args,1)); | |
304 | if ($collecte) | |
305 | {$res[] = $collecte; $collecte = array();} | |
306 | } | |
307 | } | |
308 | if ($collecte) {$res[] = $collecte; $collecte = array();} | |
309 | $args = substr($args,1); | |
310 | } | |
311 | $n = strlen($suite) - strlen($args); | |
312 | if ($fonc || count($res) > 1) $pointeur_champ->param[] = $res; | |
313 | // pour les balises avec faux filtres qui boudent ce dur larbeur | |
314 | $pointeur_champ->fonctions[] = array($fonc, substr($suite, 0, $n)); | |
315 | $texte = ltrim($args); | |
316 | return $result; | |
317 | } | |
318 | ||
319 | ||
320 | // http://doc.spip.org/@phraser_champs_exterieurs | |
321 | function phraser_champs_exterieurs($texte, $ligne, $sep, $nested) { | |
322 | $res = array(); | |
323 | while (($p=strpos($texte, "%$sep"))!==false) { | |
324 | if (!preg_match(',^%'.preg_quote($sep).'([0-9]+)@,', substr($texte,$p), $m)) | |
325 | break; | |
326 | $debut = substr($texte,0,$p); | |
327 | $texte = substr($texte, $p+strlen($m[0])); | |
328 | if ($p) | |
329 | $res = phraser_inclure($debut, $ligne, $res); | |
330 | $ligne += substr_count($debut, "\n"); | |
331 | $res[]= $nested[$m[1]]; | |
332 | } | |
333 | return (($texte==='') ? $res : phraser_inclure($texte, $ligne, $res)); | |
334 | } | |
335 | ||
336 | // http://doc.spip.org/@phraser_champs_interieurs | |
337 | function phraser_champs_interieurs($texte, $ligne, $sep, $result) { | |
338 | $i = 0; // en fait count($result) | |
339 | $x = ""; | |
340 | ||
341 | while (true) { | |
342 | $j=$i; | |
343 | $n = $ligne; | |
344 | while (ereg(CHAMP_ETENDU, $texte, $match)) { | |
345 | $p = strpos($texte, $match[0]); | |
346 | $debut = substr($texte, 0, $p); | |
347 | if ($p) { | |
348 | $result[$i] = $debut; | |
349 | $i++; | |
350 | } | |
351 | $champ = new Champ; | |
352 | // ca ne marche pas encore en cas de champ imbrique | |
353 | $champ->ligne = $x ? 0 :($n+substr_count($debut, "\n")); | |
354 | $champ->nom_boucle = $match[3]; | |
355 | $champ->nom_champ = $match[4]; | |
356 | $champ->etoile = $match[6]; | |
357 | // phraser_args indiquera ou commence apres | |
358 | $result = phraser_args($match[7], ")", $sep, $result, $champ); | |
359 | $champ->avant = | |
360 | phraser_champs_exterieurs($match[1],$n,$sep,$result); | |
361 | $debut = substr($champ->apres,1); | |
362 | $n += substr_count(substr($texte, 0, strpos($texte, $debut)), "\n"); | |
363 | $champ->apres = phraser_champs_exterieurs($debut,$n,$sep,$result); | |
364 | ||
365 | $result[$i] = $champ; | |
366 | $i++; | |
367 | $texte = substr($texte,$p+strlen($match[0])); | |
368 | } | |
369 | if ($texte!=="") {$result[$i] = $texte; $i++;} | |
370 | $x =''; | |
371 | ||
372 | while($j < $i) { | |
373 | $z= $result[$j]; | |
374 | // j'aurais besoin de connaitre le nombre de lignes... | |
375 | if (is_object($z)) | |
376 | $x .= "%$sep$j@"; | |
377 | else | |
378 | $x.=$z; | |
379 | $j++; | |
380 | } | |
381 | if (ereg(CHAMP_ETENDU, $x)) | |
382 | $texte = $x; | |
383 | else | |
384 | return phraser_champs_exterieurs($x, $ligne, $sep, $result); | |
385 | } | |
386 | } | |
387 | ||
388 | // analyse des criteres de boucle, | |
389 | ||
390 | // http://doc.spip.org/@phraser_criteres | |
391 | function phraser_criteres($params, &$result) { | |
392 | ||
393 | $args = array(); | |
394 | $type = $result->type_requete; | |
395 | $doublons = array(); | |
396 | foreach($params as $v) { | |
397 | $var = $v[1][0]; | |
398 | $param = ($var->type != 'texte') ? "" : $var->texte; | |
399 | if ((count($v) > 2) && (!eregi("[^A-Za-z]IN[^A-Za-z]",$param))) | |
400 | { | |
401 | // plus d'un argument et pas le critere IN: | |
402 | // detecter comme on peut si c'est le critere implicite LIMIT debut, fin | |
403 | ||
404 | if (($var->type != 'texte') || | |
405 | (strpos("0123456789-", $param[strlen($param)-1]) | |
406 | !== false)) { | |
407 | $op = ','; | |
408 | $not = ""; | |
409 | } else { | |
410 | preg_match("/^([!]?)([a-zA-Z][a-zA-Z0-9]*)[[:space:]]*(.*)$/ms", $param, $m); | |
411 | $op = $m[2]; | |
412 | $not = $m[1]; | |
413 | if ($m[3]) $v[1][0]->texte = $m[3]; else array_shift($v[1]); | |
414 | } | |
415 | array_shift($v); | |
416 | $crit = new Critere; | |
417 | $crit->op = $op; | |
418 | $crit->not = $not; | |
419 | $crit->param = $v; | |
420 | $args[] = $crit; | |
421 | } else { | |
422 | if ($var->type != 'texte') { | |
423 | // cas 1 seul arg ne commencant pas par du texte brut: | |
424 | // erreur ou critere infixe "/" | |
425 | if (($v[1][1]->type != 'texte') || (trim($v[1][1]->texte) !='/')) | |
426 | erreur_squelette('criteres',$var->nom_champ); | |
427 | else { | |
428 | $crit = new Critere; | |
429 | $crit->op = '/'; | |
430 | $crit->not = ""; | |
431 | $crit->param = array(array($v[1][0]),array($v[1][2])); | |
432 | $args[] = $crit; | |
433 | } | |
434 | } else { | |
435 | // traiter qq lexemes particuliers pour faciliter la suite | |
436 | // les separateurs | |
437 | if ($var->apres) | |
438 | $result->separateur[] = $param; | |
439 | elseif (($param == 'tout') OR ($param == 'tous')) | |
440 | $result->modificateur['tout'] = true; | |
441 | elseif ($param == 'plat') | |
442 | $result->modificateur['plat'] = true; | |
443 | ||
444 | // Boucle hierarchie, analyser le critere id_article - id_rubrique | |
445 | // - id_syndic, afin, dans les cas autres que {id_rubrique}, de | |
446 | // forcer {tout} pour avoir la rubrique mere... | |
447 | ||
448 | elseif (($type == 'hierarchie') && | |
449 | ($param == 'id_article' OR $param == 'id_syndic')) | |
450 | $result->modificateur['tout'] = true; | |
451 | elseif (($type == 'hierarchie') && ($param == 'id_rubrique')) | |
452 | {;} | |
453 | else { | |
454 | // pas d'emplacement statique, faut un dynamique | |
455 | /// mais il y a 2 cas qui ont les 2 ! | |
456 | if (($param == 'unique') || (ereg('^!?doublons *', $param))) | |
457 | { | |
458 | // cette variable sera inseree dans le code | |
459 | // et son nom sert d'indicateur des maintenant | |
460 | $result->doublons = '$doublons_index'; | |
461 | if ($param == 'unique') $param = 'doublons'; | |
462 | } | |
463 | elseif ($param == 'recherche') | |
464 | // meme chose (a cause de #nom_de_boucle:URL_*) | |
465 | $result->hash = true; | |
466 | if (ereg('^ *([0-9-]+) *(/) *(.+) *$', $param, $m)) { | |
467 | $crit = phraser_critere_infixe($m[1], $m[3],$v, '/', '', ''); | |
468 | } elseif (preg_match(',^(' . CHAMP_SQL_PLUS_FONC . | |
469 | ')[[:space:]]*(\??)(!?)(<=?|>=?|==?|\b(?:IN|LIKE)\b)(.*)$,is', $param, $m)) { | |
470 | $a2 = trim($m[7]); | |
471 | if (ereg("^'.*'$", $a2) OR ereg('^".*"$', $a2)) | |
472 | $a2 = substr($a2,1,-1); | |
473 | $crit = phraser_critere_infixe($m[1], $a2, $v, | |
474 | (($m[1] == 'lang_select') ? $m[1] : $m[6]), | |
475 | $m[5], $m[4]); | |
476 | } elseif (preg_match("/^([!]?)\s*(" . | |
477 | CHAMP_SQL_PLUS_FONC . | |
478 | ")\s*(\??)(.*)$/is", $param, $m)) { | |
479 | // contient aussi les comparaisons implicites ! | |
480 | ||
481 | array_shift($v); | |
482 | if ($m[6]) | |
483 | $v[0][0]->texte = $m[6]; | |
484 | else { | |
485 | array_shift($v[0]); | |
486 | if (!$v[0]) array_shift($v); | |
487 | } | |
488 | $crit = new Critere; | |
489 | $crit->op = $m[2]; | |
490 | $crit->param = $v; | |
491 | $crit->not = $m[1]; | |
492 | $crit->cond = $m[5]; | |
493 | } | |
494 | else { | |
495 | erreur_squelette(_T('zbug_critere_inconnu', | |
496 | array('critere' => $param))); | |
497 | } | |
498 | if ((!ereg('^!?doublons *', $param)) || $crit->not) | |
499 | $args[] = $crit; | |
500 | else | |
501 | $doublons[] = $crit; | |
502 | } | |
503 | } | |
504 | } | |
505 | } | |
506 | // les doublons non nies doivent etre le dernier critere | |
507 | // pour que la variable $doublon_index ait la bonne valeur | |
508 | // cf critere_doublon | |
509 | if ($doublons) $args= array_merge($args, $doublons); | |
510 | $result->criteres = $args; | |
511 | } | |
512 | ||
513 | // http://doc.spip.org/@phraser_critere_infixe | |
514 | function phraser_critere_infixe($arg1, $arg2, $args, $op, $not, $cond) | |
515 | { | |
516 | $args[0] = new Texte; | |
517 | $args[0]->texte = $arg1; | |
518 | $args[0] = array($args[0]); | |
519 | $args[1][0]->texte = $arg2; | |
520 | $crit = new Critere; | |
521 | $crit->op = $op; | |
522 | $crit->not = $not; | |
523 | $crit->cond = $cond; | |
524 | $crit->param = $args; | |
525 | return $crit; | |
526 | } | |
527 | ||
528 | // http://doc.spip.org/@public_phraser_html | |
529 | function public_phraser_html($texte, $id_parent, &$boucles, $nom, $ligne=1) { | |
530 | ||
531 | $all_res = array(); | |
532 | ||
533 | while (($p = strpos($texte, BALISE_BOUCLE)) !== false) { | |
534 | ||
535 | $result = new Boucle; | |
536 | $result->id_parent = $id_parent; | |
537 | ||
538 | # attention: reperer la premiere des 2 balises: pre_boucle ou boucle | |
539 | ||
540 | $n = ereg(BALISE_PRE_BOUCLE . '[0-9_]', $texte, $r); | |
541 | if ($n) $n = strpos($texte, $r[0]); | |
542 | if (($n === false) || ($n > $p)) { | |
543 | $debut = substr($texte, 0, $p); | |
544 | $milieu = substr($texte, $p); | |
545 | $k = strpos($milieu, '('); | |
546 | $id_boucle = trim(substr($milieu, | |
547 | strlen(BALISE_BOUCLE), | |
548 | $k - strlen(BALISE_BOUCLE))); | |
549 | $milieu = substr($milieu, $k); | |
550 | ||
551 | /* a adapter: si $n pointe sur $id_boucle ... | |
552 | if (strpos($milieu, $s)) { | |
553 | erreur_squelette(_T('zbug_erreur_boucle_syntaxe'), | |
554 | $id_boucle . | |
555 | _T('zbug_balise_b_aval')); | |
556 | } | |
557 | */ | |
558 | } else { | |
559 | $debut = substr($texte, 0, $n); | |
560 | $milieu = substr($texte, $n); | |
561 | $k = strpos($milieu, '>'); | |
562 | $id_boucle = substr($milieu, | |
563 | strlen(BALISE_PRE_BOUCLE), | |
564 | $k - strlen(BALISE_PRE_BOUCLE)); | |
565 | ||
566 | if (!ereg(BALISE_BOUCLE . $id_boucle . "[[:space:]]*\(", $milieu, $r)) | |
567 | erreur_squelette((_T('zbug_erreur_boucle_syntaxe')), $id_boucle); | |
568 | $p = strpos($milieu, $r[0]); | |
569 | $result->avant = substr($milieu, $k+1, $p-$k-1); | |
570 | $milieu = substr($milieu, $p+strlen($id_boucle)+strlen(BALISE_BOUCLE)); | |
571 | } | |
572 | $result->id_boucle = $id_boucle; | |
573 | ||
574 | preg_match(SPEC_BOUCLE, $milieu, $match); | |
575 | $milieu = substr($milieu, strlen($match[0])); | |
576 | $type = $match[1]; | |
577 | $jointures = trim($match[2]); | |
578 | if ($jointures) { | |
579 | $result->jointures = preg_split("/\s+/",$jointures); | |
580 | $result->jointures_explicites = $jointures; | |
581 | } | |
582 | ||
583 | if ($p = strpos($type, ':')) | |
584 | { | |
585 | $result->sql_serveur = substr($type,0,$p); | |
586 | $soustype = strtolower(substr($type,$p+1)); | |
587 | } | |
588 | else | |
589 | $soustype = strtolower($type); | |
590 | ||
591 | if ($soustype == 'sites') $soustype = 'syndication' ; # alias | |
592 | ||
593 | // | |
594 | // analyser les criteres et distinguer la boucle recursive | |
595 | // | |
596 | if (substr($soustype, 0, 6) == TYPE_RECURSIF) { | |
597 | $result->type_requete = TYPE_RECURSIF; | |
598 | $result->param[0] = substr($type, strlen(TYPE_RECURSIF)); | |
599 | $milieu = substr($milieu, strpos($milieu, '>')+1); | |
600 | $params = ""; | |
601 | } else { | |
602 | $result->type_requete = $soustype; | |
603 | phraser_args($milieu,">","",$all_res,$result); | |
604 | $params = substr($milieu,0,strpos($milieu,$result->apres)); | |
605 | $milieu = substr($result->apres,1); | |
606 | $result->apres = ""; | |
607 | phraser_criteres($result->param, $result); | |
608 | } | |
609 | ||
610 | // | |
611 | // Recuperer la fin : | |
612 | // | |
613 | $s = BALISE_FIN_BOUCLE . $id_boucle . ">"; | |
614 | $p = strpos($milieu, $s); | |
615 | if ($p === false) { | |
616 | erreur_squelette(_T('zbug_erreur_boucle_syntaxe'), | |
617 | _T('zbug_erreur_boucle_fermant', | |
618 | array('id'=>$id_boucle))); | |
619 | } | |
620 | ||
621 | $suite = substr($milieu, $p + strlen($s)); | |
622 | $milieu = substr($milieu, 0, $p); | |
623 | // | |
624 | // 1. Recuperer la partie conditionnelle apres | |
625 | // | |
626 | $s = BALISE_POST_BOUCLE . $id_boucle . ">"; | |
627 | $p = strpos($suite, $s); | |
628 | if ($p !== false) { | |
629 | $result->apres = substr($suite, 0, $p); | |
630 | $suite = substr($suite, $p + strlen($s)); | |
631 | } | |
632 | ||
633 | // | |
634 | // 2. Recuperer la partie alternative | |
635 | // | |
636 | $s = BALISE_ALT_BOUCLE . $id_boucle . ">"; | |
637 | $p = strpos($suite, $s); | |
638 | if ($p !== false) { | |
639 | $result->altern = substr($suite, 0, $p); | |
640 | $suite = substr($suite, $p + strlen($s)); | |
641 | } | |
642 | $result->ligne = $ligne + substr_count($debut, "\n"); | |
643 | $m = substr_count($milieu, "\n"); | |
644 | $b = substr_count($result->avant, "\n"); | |
645 | $a = substr_count($result->apres, "\n"); | |
646 | ||
647 | // envoyer la boucle au debugueur | |
648 | if ($GLOBALS['var_mode']== 'debug') { | |
649 | boucle_debug ($nom, $id_parent, $id_boucle, | |
650 | $type . $jointures, | |
651 | $params, | |
652 | $result->avant, | |
653 | $milieu, | |
654 | $result->apres, | |
655 | $result->altern); | |
656 | } | |
657 | ||
658 | $result->avant = public_phraser_html($result->avant, $id_parent,$boucles, $nom, $result->ligne); | |
659 | $result->apres = public_phraser_html($result->apres, $id_parent,$boucles, $nom, $result->ligne+$b+$m); | |
660 | $result->altern = public_phraser_html($result->altern,$id_parent,$boucles, $nom, $result->ligne+$a+$m+$b); | |
661 | $result->milieu = public_phraser_html($milieu, $id_boucle,$boucles, $nom, $result->ligne+$b); | |
662 | ||
663 | if (isset($boucles[$id_boucle])) { | |
664 | erreur_squelette(_T('zbug_erreur_boucle_syntaxe'), | |
665 | _T('zbug_erreur_boucle_double', | |
666 | array('id'=>$id_boucle))); | |
667 | } else | |
668 | $boucles[$id_boucle] = $result; | |
669 | $all_res = phraser_champs_etendus($debut, $ligne, $all_res); | |
670 | $all_res[] = &$boucles[$id_boucle]; | |
671 | $ligne += substr_count(substr($texte, 0, strpos($texte, $suite)), "\n"); | |
672 | $texte = $suite; | |
673 | } | |
674 | ||
675 | return phraser_champs_etendus($texte, $ligne, $all_res); | |
676 | } | |
677 | ?> |