#define _GNU_SOURCE /* sert à définir la fonction fcloseall(), spéciale GNU */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>

/* SHELL.C: interface avec le Bourne Shell*/
#define CODE_FIN_SHELL "FinShell-iopipoisqpodiopsidqpogisdfg-FinShell"
#define LONGUEUR_LIGNE 160
void erreur(char *format, ...);
void warning(char *format, ...);
void init_pipe(void);
void fin_pipe(void);
void envoieshell(char *s);
char *recoitshell(char *s,int retireEOL);
void execshell(char *s);
void creetemp(char *nom); /* signale la création d'un fichier temporaire,
			   * pour permettre le nettoyage si nécessaire */

/* PREHTML.C: programme principal*/
extern int debug;
extern char *fich_out,*fich_temp;
int main(int argc,char *argv[]);


/* FICHIER.C: lecture des fichiers, inclus ou non*/
/* objet pour la lecture des fichiers*/
struct _fichier{
  long numero_ligne;
  char *nom_fichier;
  FILE *fd;
  struct _fichier *pere;
};
typedef struct _fichier fichier;

extern fichier *fichier_courant;

void *monalloc(size_t size); /* comme malloc(), mais erreur fatale si pb*/
void ouvrir_fichier(char *nom); /* ouvre le premier fichier*/
void inclure_fichier(char *nom); /* ouvre un fichier inclus*/
void dit_ou(void); /* dit où on est dans le fichier, et via quelles
		    * inclusions, pour faire message d'erreur;
		    * sort dans stderr et n'inclut pas de '\n'*/
int mongetc(void); /* lit un caractère du système de fichier (EOF si fin)*/
void stocke(void); /* commence à enregistrer les car lurs par mongetc() */
void destocke(void); /* reprend la lecture à l'endroit signalé par stocke() */
void finstocke(void); /* arrête le stockage et élimine les caractères lus*/
       /* NB: on peut faire destocke et finstocke pendant la lecture de
	* caractères déjà stockés par stocke(): c'est transparent */
FILE *quelfichier(void); /* dit dans quel fichier on se trouve */
off_t queloffset(void); /* donne la position actuelle dans le fichier */
int quelleligne(void); /* idem: dit à quelle ligne on est */
void revient(FILE *fich,off_t pos,int ligne);/* tente de revenir, mais vérifie*
					      * qu'on est dans le même fichier*/

/* DECODE.C: extraction des fonctions <phtml>*/
#define EST_FONCTION (EOF!=1000?1000:1001)
extern char *listefonctions[]; /* liste de toutes les fonctions,
  avec NULL à la fin, genre {"shell","if","fi",NULL} */
char *chaine; /* chaine qui suit le code de la fonction */
extern char fonction[30]; /* nom de la fonction */
char *recodeHTML(char *s); /* fait les échappements HTML, et alloue de
			    * la mémoire pour la chaîne résultante*/
int decode(void); /* renvoie un caractère, ou EOF si fini,
		   * ou EST_FONCTION si a trouvé un fonction
		   * (ce qui demande de lire quelle_fonction() )*/

/* IMBRIQUE.C: gère les imbrications */
/* définition de types pour les imbrications */
typedef struct {
  int estvrai; /* valeur de la condition */
} infoif;
typedef struct {
  char **liste; /* liste des valeurs que doit prendre la variable, puis NULL*/
  FILE *fichier; /* fichier où l'on est (doit être le même à la fin!)*/
  off_t pos; /* position dans ce fichier */
  int ligne; /* numéro de la ligne courante */
  char *var; /*nom de la variable qui varie*/
  int numval; /*numéro de la valeur de la variable en cours*/
} infofor;
typedef struct {
  char *condition; /* condition du while*/
  FILE *fichier; /* fichier où l'on est (doit être le même à la fin!)*/
  off_t pos; /* position dans ce fichier, après le <WHILE> */
  int ligne; /* numéro de la ligne courante */
} infowhile;
typedef struct {
  char **liste; /* liste des fichiers à inclure */
  int affiche; /* vrai si on devait afficher, avant de rentrer en inclusion*/
  int numfich; /* numéro du fichier que l'on inclut */
} infoinclude;

typedef union{
  infoif pourif;
  infofor pourfor;
  infowhile pourwhile;
  infoinclude pourinclude;
} infounion;

typedef struct _imbrique{
  enum {MAIN,IF,FOR,WHILE,INCLUDE
  } type;
  infounion info;
  struct _imbrique *precedent;
} imbrique;

extern imbrique *imbriqueactu; /* dit dans quelle imbrications nous sommes*/

char *typeimbrique(imbrique *i); /* donne le nom d'une imbrication */
int attend(char *etiq); /* trouve le champ "etiq" correspondant sans
			  * exécuter le code intermédiaire, mais en
			  * faisant attention aux imbrications*/
  /* si etiq="else", renvoie 1 si trouvé, et 0 si a rencontré "fi" */
void referme_imbrique(void); /* referme l'imbrication courant */
void ouvre_imbrique(void); /* operations génériques pour tous les types */

/* FONCTION.C: quand on a reçu une fonction, fait presque tout */
extern int flag_reinclude; /* le prochain fichier inclus doit-il être
			      * inclus avec son entête, remplaçant l'ancien? */
extern int affiche; /* vrai si on doit afficher ce qu'on lit*/
extern int chut; /* vrai si on a cache un morceau */
extern FILE *sortie;
void print(char *format, ...); /* écrit dans le fichier cible (sortie) */
void put(char c); /* idem, mais imite putc() au lieu de fprintf */
int vraifaux(char *commande,char *condition); /* utilisé par IF et WHILE */
void traitefonction(void); /* fait presque tout */

/* GENERATE.C: gestion de <generate> et </generate> */
typedef struct structgenerate{
  char *nomtemp;
  char *nom;
  struct structgenerate *suivant;
} generate;

extern int engenerate; /* 0=pas de générate, 1=dans générate
			* 2=generate passé */
void init_generate(void);
void genere(char *s); /* correspond à <GENERATE> */
void degenere(void); /* fonction appelée quand </generate> arrive */
void fin_generate(void); /* choses à faire à la fin du fichier principal pour
			  * finaliser les <GENERATE> éventuels */
