Subversion Repositories Sites.tela-botanica.org

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 david 1
<?php
2
 
3
/***************************************************************************\
4
 *  SPIP, Systeme de publication pour l'internet                           *
5
 *                                                                         *
6
 *  Copyright (c) 2001-2005                                                *
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
//
15
// Fichier principal du compilateur de squelettes
16
//
17
 
18
// Ce fichier ne sera execute qu'une fois
19
if (defined("_INC_COMPILO")) return;
20
define("_INC_COMPILO", "1");
21
 
22
// reperer un code ne calculant rien, meme avec commentaire
23
define('CODE_MONOTONE', "^(\n//[^\n]*\n)?\(?'([^'])*'\)?$");
24
 
25
// Definition de la structure $p, et fonctions de recherche et de reservation
26
// dans l'arborescence des boucles
27
include_local("inc-compilo-index.php3");  # index ? structure ? pile ?
28
 
29
// definition des boucles
30
include_local("inc-boucles.php3");
31
 
32
// definition des criteres
33
include_local("inc-criteres.php3");
34
 
35
// definition des balises
36
include_local("inc-balises.php3");
37
 
38
// definition de l'API
39
include_local("inc-compilo-api.php3");
40
 
41
# definition des tables
42
include_ecrire('inc_serialbase.php3');
43
 
44
// outils pour debugguer le compilateur
45
#include_local("inc-compilo-debug.php3"); # desactive
46
 
47
//
48
// Calculer un <INCLURE()>
49
//
50
function calculer_inclure($struct, $descr, &$boucles, $id_boucle) {
51
	$fichier = $struct->texte;
52
 
53
	if (!($path = find_in_path($fichier)))
54
	  {
55
		spip_log("ERREUR: <INCLURE($fichier)> impossible");
56
		erreur_squelette(_T('zbug_info_erreur_squelette'),
57
				 "&lt;INCLURE($fichier)&gt; - "
58
				 ._T('fichier_introuvable', array('fichier' => $fichier)));
59
		return "'<!-- Erreur INCLURE(".texte_script($fichier).") -->'";
60
	}
61
 
62
	$l = array();
63
	foreach($struct->param as $val) {
64
		$var = array_shift($val);
65
		$l[] = "\'$var\' => \'' . addslashes(" .
66
		    ($val ? calculer_liste($val[0], $descr, $boucles, $id_boucle) :
67
		    (($var =='lang') ?
68
		     '$GLOBALS["spip_lang"]' :
69
		     index_pile($id_boucle, $var, $boucles)))
70
		    . ") . '\\'";
71
		}
72
 
73
	return "\n'<".
74
		"?php\n\t\$contexte_inclus = array(" .
75
		join(",\n\t",$l) .
76
		");" .
77
		"\n\tinclude(\\'$path\\');" .
78
		"\n?'." . "'>'";
79
 }
80
 
81
//
82
// calculer_boucle() produit le corps PHP d'une boucle Spip
83
// Sauf pour les recursives, ce corps est un Select SQL + While PHP
84
// remplissant une variable $t0 retournee en valeur
85
//
86
function calculer_boucle($id_boucle, &$boucles) {
87
 
88
  $boucle = &$boucles[$id_boucle];
89
  $return = $boucle->return;
90
  $type_boucle = $boucle->type_requete;
91
 
92
  if ($type_boucle == 'boucle') {
93
	    $corps = "\n	\$t0 = " . $return . ";";
94
	    $init = "";
95
  } else {
96
	$primary = $boucle->primary;
97
	$constant = ereg(CODE_MONOTONE,$return);
98
 
99
	// Cas {1/3} {1,4} {n-2,1}...
100
 
101
	$flag_cpt = $boucle->mode_partie || // pas '$compteur' a cause du cas 0
102
	  strpos($return,'compteur_boucle');
103
 
104
	//
105
	// Creer le debut du corps de la boucle :
106
	//
107
	$corps = '';
108
	if ($flag_cpt)
109
		$corps = "\n		\$Numrows['$id_boucle']['compteur_boucle']++;";
110
 
111
	if ($boucle->mode_partie)
112
		$corps .= "
113
		if (\$Numrows['$id_boucle']['compteur_boucle']-1 >= \$debut_boucle
114
		AND \$Numrows['$id_boucle']['compteur_boucle']-1 <= \$fin_boucle) {";
115
 
116
	// Calculer les invalideurs si c'est une boucle non constante
117
 
118
	if ($primary && !$constant)
119
		$corps .= "\n\t\t\$Cache['$primary'][" .
120
		  (($primary != 'id_forum')  ?
121
		   index_pile($id_boucle, $primary, $boucles) :
122
		   ("calcul_index_forum(" .
123
		// Retournera 4 [$SP] mais force la demande du champ a MySQL
124
		    index_pile($id_boucle, 'id_article', $boucles) . ',' .
125
		    index_pile($id_boucle, 'id_breve', $boucles) .  ',' .
126
		    index_pile($id_boucle, 'id_rubrique', $boucles) .',' .
127
		    index_pile($id_boucle, 'id_syndic', $boucles) .
128
		    ")")) .
129
		  "] = 1; // invalideurs\n";
130
 
131
	if ($boucle->doublons)
132
		$corps .= "		\$doublons[".$boucle->doublons."] .= ','. " .
133
		index_pile($id_boucle, $primary, $boucles)
134
		. "; // doublons\n";
135
 
136
 
137
	if (count($boucle->separateur))
138
	  $code_sep = ("'" . ereg_replace("'","\'",join('',$boucle->separateur)) . "'");
139
 
140
	$init = '';
141
	$fin = '';
142
 
143
	// La boucle doit-elle selectionner la langue ?
144
	// -. par defaut, les boucles suivantes le font
145
	// "peut-etre", c'est-a-dire si forcer_lang == false.
146
	// - . a moins d'une demande explicite
147
	if (!$constant && $boucle->lang_select != 'non' &&
148
	    (($boucle->lang_select == 'oui')  ||
149
		    (
150
			$type_boucle == 'articles'
151
			OR $type_boucle == 'rubriques'
152
			OR $type_boucle == 'hierarchie'
153
			OR $type_boucle == 'breves'
154
			)))
155
	  {
156
	      $corps .=
157
		  (($boucle->lang_select != 'oui') ?
158
			"\t\tif (!\$GLOBALS['forcer_lang'])\n\t " : '')
159
		  . "\t\t\$GLOBALS['spip_lang'] = (\$x = "
160
		  . index_pile($id_boucle, 'lang', $boucles)
161
		  . ') ? $x : $old_lang;';
162
		// Memoriser la langue avant la boucle pour la restituer apres
163
	      $init .= "\n	\$old_lang = \$GLOBALS['spip_lang'];";
164
	      $fin .= "\n	\$GLOBALS['spip_lang'] = \$old_lang;";
165
 
166
	  }
167
 
168
	// gestion optimale des separateurs et des boucles constantes
169
	$corps .=
170
		((!$boucle->separateur) ?
171
			(($constant && !$corps) ? $return :
172
			 	("\n\t\t" . '$t0 .= ' . $return . ";")) :
173
		 ("\n\t\t\$t1 " .
174
			((strpos($return, '$t1.') === 0) ?
175
			 (".=" . substr($return,4)) :
176
			 ('= ' . $return)) .
177
		  ";\n\t\t" .
178
		  '$t0 .= (($t1 && $t0) ? ' . $code_sep . " : '') . \$t1;"));
179
 
180
	// Fin de parties
181
	if ($boucle->mode_partie)
182
		$corps .= "\n		}\n";
183
 
184
	// Gestion de la hierarchie (voir inc-boucles.php3)
185
	if ($boucle->hierarchie)
186
		$init .= "\n	".$boucle->hierarchie;
187
 
188
	// si le corps est une constante, ne pas appeler le serveur N fois!
189
	if (ereg(CODE_MONOTONE,$corps, $r)) {
190
		if (!$r[2]) {
191
			if (!$boucle->numrows)
192
				return 'return "";';
193
			else
194
				$corps = "";
195
		} else {
196
			$boucle->numrows = true;
197
			$corps = "\n	".'for($x=$Numrows["'.$id_boucle.'"]["total"];$x>0;$x--)
198
			$t0 .= ' . $corps .';';
199
		}
200
	} else {
201
 
202
		$corps = '
203
 
204
	// RESULTATS
205
	while ($Pile[$SP] = @spip_abstract_fetch($result,"' .
206
		  $boucle->sql_serveur .
207
		  '")) {' .
208
		  "\n$corps\n	}\n" .
209
		  $fin ;
210
	}
211
 
212
	//
213
	// Requete
214
	//
215
 
216
	if (!$order = $boucle->order
217
	AND !$order = $boucle->default_order)
218
		$order = array();
219
 
220
	$init .= $boucle->hash .
221
	  "\n\n	// REQUETE
222
	\$result = spip_abstract_select(\n\t\tarray(\"".
223
		# En absence de champ c'est un decompte :
224
	  	# prendre la primary pour avoir qqch
225
	  	# (COUNT incompatible avec le cas general
226
		($boucle->select ?
227
		 join("\",\n\t\t\"", $boucle->select) :
228
		 ($boucle->id_table . "." .
229
		 (($p = strpos($primary, ',')) ?
230
		  substr($primary, 0, $p) : $primary))) .
231
		'"), # SELECT
232
		array("' .
233
		join('","', array_unique($boucle->from)) .
234
		'"), # FROM
235
		array(' .
236
		(!$boucle->where ? '' : ( '"' . join('",
237
		"', $boucle->where) . '"')) .
238
		"), # WHERE
239
		'".addslashes($boucle->group)."', # GROUP
240
		array(" .
241
	  	join(', ', $order) .
242
		"), # ORDER
243
		" . (strpos($boucle->limit, 'intval') === false ?
244
			"'".$boucle->limit."'" :
245
			$boucle->limit). ", # LIMIT
246
		'".$boucle->sous_requete."', # sous
247
		'" . (!$boucle->having ? "" : "(COUNT(*)> $boucle->having)")."', # HAVING
248
		'".$boucle->id_table."', # table
249
		'".$boucle->id_boucle."', # boucle
250
		'".$boucle->sql_serveur."'); # serveur";
251
 
252
	$init .= "\n	".'$t0 = "";
253
	$SP++;';
254
	if ($flag_cpt)
255
		$init .= "\n	\$Numrows['$id_boucle']['compteur_boucle'] = 0;";
256
 
257
	if ($boucle->mode_partie)
258
		$init .= calculer_parties($boucles, $id_boucle);
259
	else if ($boucle->numrows)
260
		$init .= "\n	\$Numrows['" .
261
			$id_boucle .
262
			"']['total'] = @spip_abstract_count(\$result,'" .
263
			$boucle->sql_serveur .
264
			"');";
265
 
266
	//
267
	// Conclusion et retour
268
	//
269
	$corps .= "\n	@spip_abstract_free(\$result,'" .
270
	     $boucle->sql_serveur . "');";
271
 
272
  }
273
 
274
  return $init . $corps .
275
	## inserer le code d'envoi au debusqueur du resultat de la fonction
276
	(($GLOBALS['var_mode_affiche'] != 'resultat') ? "" : "
277
		boucle_debug_resultat('$id_boucle', 'resultat', \$t0);") .
278
    "\n	return \$t0;";
279
 
280
 
281
}
282
 
283
 
284
//
285
// fonction traitant les criteres {1,n} (analyses dans inc-criteres)
286
//
287
## a deplacer dans inc-criteres ??
288
function calculer_parties($boucles, $id_boucle) {
289
 
290
	$boucle = &$boucles[$id_boucle];
291
	$partie = $boucle->partie;
292
	$mode_partie = $boucle->mode_partie;
293
	$total_parties = $boucle->total_parties;
294
 
295
	// Notes :
296
	// $debut_boucle et $fin_boucle sont les indices SQL du premier
297
	// et du dernier demandes dans la boucle : 0 pour le premier,
298
	// n-1 pour le dernier ; donc total_boucle = 1 + debut - fin
299
 
300
	// nombre total avant partition
301
	$retour = "\n\n	// Partition\n	" .
302
		'$nombre_boucle = @spip_abstract_count($result,"' .
303
		$boucle->sql_serveur .
304
		'");';
305
 
306
	ereg("([+-/])([+-/])?", $mode_partie, $regs);
307
	list(,$op1,$op2) = $regs;
308
 
309
	// {1/3}
310
	if ($op1 == '/') {
311
		$pmoins1 = is_numeric($partie) ? ($partie-1) : "($partie-1)";
312
		$totpos = is_numeric($total_parties) ? ($total_parties) :
313
		  "($total_parties ? $total_parties : 1)";
314
		$retour .= "\n	"
315
		  .'$debut_boucle = ceil(($nombre_boucle * '
316
		  . $pmoins1 . ')/' . $totpos . ");";
317
		$fin = 'ceil (($nombre_boucle * '
318
			. $partie . ')/' . $totpos . ") - 1";
319
	}
320
 
321
	// {1,x}
322
	elseif ($op1 == '+') {
323
		$retour .= "\n	"
324
			. '$debut_boucle = ' . $partie . ';';
325
	}
326
	// {n-1,x}
327
	elseif ($op1 == '-') {
328
		$retour .= "\n	"
329
			. '$debut_boucle = $nombre_boucle - ' . $partie . ';';
330
	}
331
	// {x,1}
332
	if ($op2 == '+') {
333
		$fin = '$debut_boucle'
334
		  . (is_numeric($total_parties) ?
335
		     (($total_parties==1) ? "" :(' + ' . ($total_parties-1))):
336
		     ('+' . $total_parties . ' - 1'));
337
	}
338
	// {x,n-1}
339
	elseif ($op2 == '-') {
340
		$fin = '$debut_boucle + $nombre_boucle - '
341
		  . (is_numeric($total_parties) ? ($total_parties+1) :
342
		     ($total_parties . ' - 1'));
343
	}
344
 
345
	// Rabattre $fin_boucle sur le maximum
346
	$retour .= "\n	"
347
		.'$fin_boucle = min(' . $fin . ', $nombre_boucle - 1);';
348
 
349
	// calcul du total boucle final
350
	$retour .= "\n	"
351
		.'$Numrows[\''.$id_boucle.'\']["total"] = max(0,$fin_boucle - $debut_boucle + 1);';
352
 
353
	return $retour;
354
}
355
 
356
// Production du code PHP a partir de la sequence livree par le phraseur
357
// $boucles est passe par reference pour affectation par index_pile.
358
// Retourne une expression PHP,
359
// (qui sera argument d'un Return ou la partie droite d'une affectation).
360
 
361
function calculer_liste($tableau, $descr, &$boucles, $id_boucle='') {
362
	if (!$tableau) return "''";
363
	$codes = compile_cas($tableau, $descr, $boucles, $id_boucle);
364
	$n = count($codes);
365
	if (!$n) return "''";
366
	if ($GLOBALS['var_mode_affiche'] != 'validation')
367
	  return
368
		(($n==1) ? $codes[0] :
369
			 "(" . join (" .\n$tab", $codes) . ")");
370
	else return "debug_sequence('$id_boucle', '" .
371
	  ($descr['nom']) .
372
	  "', " .
373
	  intval($descr['niv']) .
374
	  ",  array(" .
375
	  join(" ,\n$tab", $codes) . "))";
376
}
377
 
378
function compile_cas($tableau, $descr, &$boucles, $id_boucle='') {
379
        $codes = array();
380
	// cas de la boucle recursive
381
	if (is_array($id_boucle))
382
	  $id_boucle = $id_boucle[0];
383
	$type = $boucles[$id_boucle]->type_requete;
384
	$descr['niv']++;
385
	for ($i=0; $i<=$descr['niv']; $i++) $tab .= "\t";
386
 
387
	// chaque commentaire introduit dans le code doit commencer
388
	// par un caractere distinguant le cas, pour exploitation par debug.
389
	foreach ($tableau as $p) {
390
 
391
		switch($p->type) {
392
		// texte seul
393
		case 'texte':
394
			$code = "'".ereg_replace("([\\\\'])", "\\\\1", $p->texte)."'";
395
 
396
			$commentaire= strlen($p->texte) . " signes";
397
			$avant='';
398
			$apres='';
399
			$altern = "''";
400
			break;
401
 
402
		case 'polyglotte':
403
			$code = "";
404
			foreach($p->traductions as $k => $v) {
405
			  $code .= ",'" .
406
			    ereg_replace("([\\\\'])", "\\\\1", $k) .
407
			    "' => '" .
408
			    ereg_replace("([\\\\'])", "\\\\1", $v) .
409
			    "'";
410
			}
411
			$code = "multi_trad(array(" .
412
 			  substr($code,1) .
413
			  "))";
414
			$commentaire= '&';
415
			$avant='';
416
			$apres='';
417
			$altern = "''";
418
			break;
419
 
420
		// inclure
421
		case 'include':
422
			$code = calculer_inclure($p, $descr, $boucles, $id_boucle);
423
			$commentaire = '!' . $p->texte;
424
			$avant='';
425
			$apres='';
426
			$altern = "''";
427
			break;
428
 
429
		// boucle
430
		case 'boucle':
431
			$nom = $p->id_boucle;
432
			$newdescr = $descr;
433
			$newdescr['id_mere'] = $nom;
434
			$newdescr['niv']++;
435
			$code = 'BOUCLE' .
436
			  ereg_replace("-","_", $nom) . $descr['nom'] .
437
			  '($Cache, $Pile, $doublons, $Numrows, $SP)';
438
			$commentaire= "?$nom";
439
			$avant = calculer_liste($p->avant,
440
				$newdescr, $boucles, $id_boucle);
441
			$apres = calculer_liste($p->apres,
442
				$newdescr, $boucles, $id_boucle);
443
			$newdescr['niv']--;
444
			$altern = calculer_liste($p->altern,
445
				$newdescr, $boucles, $id_boucle);
446
			break;
447
 
448
		case 'idiome':
449
			$p->code = "_T('" . $p->module . ":" .$p->nom_champ . "')";
450
			$p->id_boucle = $id_boucle;
451
			$p->boucles = &$boucles;
452
			$p->statut = 'php'; // ne pas manger les espaces avec trim()
453
			$commentaire = ":";
454
			$code = applique_filtres($p);
455
			$avant='';
456
			$apres='';
457
			$altern = "''";
458
			break;
459
 
460
		case 'champ';
461
 
462
			// cette structure pourrait etre completee des le phrase' (a faire)
463
			$p->id_boucle = $id_boucle;
464
			$p->boucles = &$boucles;
465
			$p->descr = $descr;
466
			$p->statut = 'html';
467
			$p->type_requete = $type;
468
 
469
			$code = calculer_champ($p);
470
			$commentaire = '#' . $p->nom_champ . $p->etoile;
471
			$avant = calculer_liste($p->avant,
472
				$descr, $boucles, $id_boucle);
473
			$apres = calculer_liste($p->apres,
474
				$descr, $boucles, $id_boucle);
475
			$altern = "''";
476
			break;
477
 
478
		default:
479
		  erreur_squelette(_T('zbug_info_erreur_squelette'));
480
		} // switch
481
 
482
		if ($avant == "''") $avant = '';
483
		if ($apres == "''") $apres = '';
484
		if ($avant||$apres||($altern!="''"))
485
		  {
486
		    $t = '$t' . $descr['niv'];
487
		    $res = (!$avant ? "" : "$avant . ") .
488
		      $t .
489
		      (!$apres ? "" : " . $apres");
490
		    $code = "(($t = $code) ?\n\t$tab($res) :\n\t$tab($altern))";
491
		  }
492
		if ($code != "''")
493
		  $codes[]= (($GLOBALS['var_mode_affiche'] == 'validation') ?
494
			     "array(" . $p->ligne . ", '$commentaire', $code)"
495
			     : (($GLOBALS['var_mode_affiche'] == 'code') ?
496
				"\n// $commentaire\n$code" :
497
				$code));
498
	} // foreach
499
	return $codes;
500
}
501
 
502
// affichage du code produit
503
 
504
function code_boucle(&$boucles, $id, $nom)
505
{
506
	$boucle = &$boucles[$id];
507
 
508
	// Indiquer la boucle en commentaire
509
	$pretty = '';
510
 
511
	if ($boucle->type_requete != 'boucle')
512
	  {
513
	    // Resynthetiser les criteres
514
	    foreach ($boucle->param as $param) {
515
	      $s = "";
516
	      $sep = "";
517
	      foreach ($param as $t) {
518
		if (is_array($t)) { // toujours vrai normalement
519
		  $s .= $sep;
520
		  $c = $t[0];
521
		  if ($c->apres)
522
		    $s .= ($c->apres . $c->texte . $c->apres);
523
		  else {
524
		// faudrait decompiler aussi les balises...
525
		    foreach ($t as $c)
526
		      $s .=  ($c->type == 'texte') ? $c->texte : '#...';
527
		  }
528
		  $sep = ", ";
529
		}
530
	      }
531
	      $pretty .= ' {' . $s . '}';
532
	    }
533
	  }
534
 
535
	$pretty = "BOUCLE$id(".strtoupper($boucle->type_requete) . ")" .
536
		ereg_replace("[\r\n]", " ", $pretty);
537
 
538
	return $pretty;
539
}
540
 
541
 
542
// Prend en argument le source d'un squelette, sa grammaire et un nom.
543
// Retourne une fonction PHP/SQL portant ce nom et calculant une page HTML.
544
// Pour appeler la fonction produite, lui fournir 2 tableaux de 1 e'le'ment:
545
// - 1er: element 'cache' => nom (du fichier ou` mettre la page)
546
// - 2e: element 0 contenant un environnement ('id_article => $id_article, etc)
547
// Elle retourne alors un tableau de 4 e'le'ments:
548
// - 'texte' => page HTML, application du squelette a` l'environnement;
549
// - 'squelette' => le nom du squelette
550
// - 'process_ins' => 'html' ou 'php' selon la pre'sence de PHP dynamique
551
// - 'invalideurs' =>  de'pendances de cette page, pour invalider son cache.
552
// (voir son utilisation, optionnelle, dans invalideur.php)
553
// En cas d'erreur, elle retourne un tableau des 2 premiers elements seulement
554
 
555
function calculer_squelette($squelette, $nom, $gram, $sourcefile) {
556
# 3 variables qui sont en fait des constantes après chargement
557
  global $table_primary, $table_des_tables, $tables_des_serveurs_sql;
558
	// Phraser le squelette, selon sa grammaire
559
	// pour le moment: "html" seul connu (HTML+balises BOUCLE)
560
	$boucles = array();
561
	spip_timer('calcul_skel');
562
 
563
	include_local("inc-$gram-squel.php3");
564
 
565
	$racine = phraser($squelette, '',$boucles, $nom);
566
 
567
	// tableau des informations sur le squelette
568
	$descr = array('nom' => $nom, 'documents' => false, 'sourcefile' => $sourcefile);
569
 
570
	// une boucle documents est conditionnee par tout le reste!
571
	foreach($boucles as $idb => $boucle) {
572
		if (($boucle->type_requete == 'documents') && $boucle->doublons)
573
			{ $descr['documents'] = true; break; }
574
	}
575
	// Commencer par reperer les boucles appelees explicitement
576
	// car elles indexent les arguments de maniere derogatoire
577
	foreach($boucles as $id => $boucle) {
578
		if ($boucle->type_requete == 'boucle') {
579
			$rec = &$boucles[$boucle->param[0]];
580
			if (!$rec) {
581
				return array(_T('zbug_info_erreur_squelette'),
582
						($boucle->param[0]
583
						. ' '. _T('zbug_boucle_recursive_undef')));
584
			} else {
585
				$rec->externe = $id;
586
				$descr['id_mere'] = $id;
587
				$boucles[$id]->return =
588
						calculer_liste(array($rec),
589
							 $descr,
590
							 $boucles,
591
							 $boucle->param);
592
			}
593
		}
594
	}
595
	foreach($boucles as $id => $boucle) {
596
		$type = $boucle->type_requete;
597
		if ($type != 'boucle') {
598
			$boucles[$id]->id_table = $table_des_tables[$type];
599
			if ($boucles[$id]->id_table) {
600
				$boucles[$id]->primary = $table_primary[$type];
601
			} else {
602
				// table non Spip.
603
				$boucles[$id]->id_table = $type;
604
				$serveur = $boucle->sql_serveur;
605
				$x = &$tables_des_serveurs_sql[$serveur ? $serveur : 'localhost'][$type]['key'];
606
				$boucles[$id]->primary = ($x["PRIMARY KEY"] ? $x["PRIMARY KEY"] : $x["KEY"]);
607
			}
608
			if ($boucle->param) {
609
				$res = calculer_criteres($id, $boucles);
610
				if (is_array($res)) return $res; # erreur
611
			}
612
			$descr['id_mere'] = $id;
613
			$boucles[$id]->return =
614
			  calculer_liste($boucle->milieu,
615
					 $descr,
616
					 $boucles,
617
					 $id);
618
			}
619
	}
620
 
621
	// idem pour la racine
622
	$descr['id_mere'] = '';
623
	$corps = calculer_liste($racine, $descr, $boucles);
624
 
625
	// Calcul du corps de toutes les fonctions PHP,
626
	// en particulier les requetes SQL et TOTAL_BOUCLE
627
	// de'terminables seulement maintenant
628
	//  Les 4 premiers parame`tres sont passe's par re'fe'rence
629
	// (les 1er et 3e pour modif, les 2 et 4 pour gain de place)
630
 
631
	foreach($boucles as $id => $boucle) {
632
		// appeler la fonction de definition de la boucle
633
		$f = 'boucle_'.strtoupper($boucle->type_requete);
634
		// si pas de definition perso, definition spip
635
		if (!function_exists($f)) $f = $f.'_dist';
636
		// laquelle a une definition par defaut
637
		if (!function_exists($f)) $f = 'boucle_DEFAUT';
638
		$boucles[$id]->return =
639
			"function BOUCLE" . ereg_replace("-","_",$id) . $nom .
640
			'(&$Cache, &$Pile, &$doublons, &$Numrows, $SP) {' .
641
			$f($id, $boucles) .
642
			"\n}\n\n";
643
		if ($GLOBALS['var_mode'] == 'debug')
644
		  boucle_debug_compile ($id, $nom, $boucles[$id]->return);
645
 
646
	}
647
 
648
	$code = "";
649
	foreach($boucles as $id => $boucle) {
650
		$code .= "\n//\n// <BOUCLE " .
651
#		  code_boucle($boucles, $id, $nom). # pas au point
652
		  $boucle->type_requete .
653
		  ">\n//\n" .
654
		  $boucle->return;
655
	}
656
 
657
	$secondes = spip_timer('calcul_skel');
658
	spip_log("calcul skel $sourcefile ($secondes)");
659
 
660
	$squelette_compile = "<"."?php
661
/*
662
 * Squelette : $sourcefile
663
 * Date :      ".http_gmoddate(@filemtime($sourcefile))." GMT
664
 * Compile :   ".http_gmoddate(time())." GMT ($secondes)
665
 * " . (!$boucles ?  "Pas de boucle" :
666
	("Boucles :   " . join (', ', array_keys($boucles)))) ."
667
 */ " .
668
	  $code . "
669
 
670
//
671
// Fonction principale du squelette $sourcefile
672
//
673
function $nom (\$Cache, \$Pile, \$doublons=array(), \$Numrows='', \$SP=0) {
674
\$t0 = $corps;
675
 
676
	return array(
677
		'texte' => \$t0,
678
		'squelette' => '$nom',
679
		'process_ins' => ((strpos(\$t0,'<'.'?')=== false) ? 'html' : 'php'),
680
		'invalideurs' => \$Cache
681
	);
682
}
683
 
684
?".">";
685
 
686
	if ($GLOBALS['var_mode'] == 'debug')
687
	  squelette_debug_compile($nom, $sourcefile, $squelette_compile, $squelette);
688
	return $squelette_compile;
689
 
690
}
691
 
692
?>