#include "prehtml.h"

char *listefonctions[]={
  "shell","echo","echonoesc","tag",
    "shellecho","shellechonoesc",
    "chut","/chut","error","warning",    /* commandes immédiates*/
    "if","else","fi","for","while","done", 
    "include","notinclude","reinclude",  /* commandes imbriquées*/
    "generate","/generate", /* pas immédiates, mais pas imbricables */
    "body","/body",   /* pour l'inclusion du corps seul, sans entêtes */
    NULL                    /* c'est tout!*/
};
static int a_decoder; /* vrai si fonction type "&lt;if"*/
static int a_decoder_link; /* vrai si fonction type "%3Cecho%20$lien%3E" */

char *chaine; /* chaine qui suit le code de la fonction */
static int longueur; /* taille réservée pour chaine*/
static int pchaine; /*nb de caractères rentrés dans chaine */
char fonction[30]; /* nom de la fonction */

static struct{char c,code[7];} escape[]={
{'"',"quot\0"}, /* le recodage est facultatif */
{'&',"amp\0"},
{'<',"lt\0"},
{'>',"gt\0"},
{' ',"nbsp\0"}, /* seulement décoder, pas recoder */
{'¡',"iexcl\0"},
{'¢',"cent\0"},
{'£',"pound\0"},
{'¤',"euro\0"}, // ça, c'est en fait du iso-8859-15 et non -1 (sinon ce serait "curren")
{'¥',"yen\0"},
{'¦',"brvbar\0"},
{'§',"sect\0"},
{'¨',"uml\0"},
{'©',"copy\0"},
{'ª',"ordf\0"},
{'«',"laquo\0"},
{'¬',"not\0"},
{'­',"shy\0"},
{'®',"reg\0"},
{'¯',"macr\0"},
{'°',"deg\0"},
{'±',"plusmn\0"},
{'²',"sup2\0"},
{'³',"sup3\0"},
{'´',"acute\0"},
{'µ',"micro\0"},
{'¶',"para\0"},
{'·',"middot\0"},
{'¸',"cedil\0"},
{'¹',"sup1\0"},
{'º',"ordm\0"},
{'»',"raquo\0"},
{'¼',"frac14\0"},
{'½',"frac12\0"},
{'¾',"frac34\0"},
{'¿',"iquest\0"},
{'À',"Agrave\0"},
{'Á',"Aacute\0"},
{'Â',"Acirc\0"},
{'Ã',"Atilde\0"},
{'Ä',"Auml\0"},
{'Å',"Aring\0"},
{'Æ',"AElig\0"},
{'Ç',"Ccedil\0"},
{'È',"Egrave\0"},
{'É',"Eacute\0"},
{'Ê',"Ecirc\0"},
{'Ë',"Euml\0"},
{'Ì',"Igrave\0"},
{'Í',"Iacute\0"},
{'Î',"Icirc\0"},
{'Ï',"Iuml\0"},
{'Ð',"ETH\0"},
{'Ñ',"Ntilde\0"},
{'Ò',"Ograve\0"},
{'Ó',"Oacute\0"},
{'Ô',"Ocirc\0"},
{'Õ',"Otilde\0"},
{'Ö',"Ouml\0"},
{'×',"times\0"},
{'Ø',"Oslash\0"},
{'Ù',"Ugrave\0"},
{'Ú',"Uacute\0"},
{'Û',"Ucirc\0"},
{'Ü',"Uuml\0"},
{'Ý',"Yacute\0"},
{'Þ',"THORN\0"},
{'ß',"szlig\0"},
{'à',"agrave\0"},
{'á',"aacute\0"},
{'â',"acirc\0"},
{'ã',"atilde\0"},
{'ä',"auml\0"},
{'å',"aring\0"},
{'æ',"aelig\0"},
{'ç',"ccedil\0"},
{'è',"egrave\0"},
{'é',"eacute\0"},
{'ê',"ecirc\0"},
{'ë',"euml\0"},
{'ì',"igrave\0"},
{'í',"iacute\0"},
{'î',"icirc\0"},
{'ï',"iuml\0"},
{'ð',"eth\0"},
{'ñ',"ntilde\0"},
{'ò',"ograve\0"},
{'ó',"oacute\0"},
{'ô',"ocirc\0"},
{'õ',"otilde\0"},
{'ö',"ouml\0"},
{'÷',"divide\0"},
{'ø',"oslash\0"},
{'ù',"ugrave\0"},
{'ú',"uacute\0"},
{'û',"ucirc\0"},
{'ü',"uuml\0"},
{'ý',"yacute\0"},
{'þ',"thorn\0"},
{'ÿ',"yuml\0"},
{'\0',"\0"}};
  
char *recodeHTML(char *s){ /* fait les échappements HTML, et alloue de
			    * la mémoire pour la chaîne résultante*/
  char *ligne;
  int longueur,pligne=0,in=0,i,car;
  ligne=monalloc(longueur=LONGUEUR_LIGNE);
  while((car=s[in])){
    if (a_decoder_link){ // recodage de type "liens"
      // la ligne suivante servait à coder les espaces en '+', mais je l'ai enlevée
      /*if (car==' ') {car='+'; ligne[pligne++]=car;} // codage spécial des espaces
      else */if (car<=0x22 || (car >=0x25 && car<0x29) || car==0x2b || car==0x3c || car==0x3e ||
	       car==0x5b || car==0x5d || car==0x5e || car==0x60 || car>=0x7b){
	//	liste des caractères à échapper:
	// <20,   20' ', 21 22 '!"', 25'%', 26??? '&', 27 28 29 ''()', 2B'+', 3c 3e '<>',
	// 5b 5d 5e '[]^', 60 '`', 7b 7c 7d 7e 7f '{|}~DEL', >=80
	ligne[pligne]='%';
	i=(car & 0xF0)>>4;
	ligne[pligne+1]=(i<10?'0'+i:'A'+i-10);
	i=(car & 0xF);
	ligne[pligne+2]=(i<10?'0'+i:'A'+i-10);
	pligne+=3;
      } else // caractère normal
	ligne[pligne++]=car;
    } else { // recodage normal, type "HTML"
      for(i=0;escape[i].c;i++){
	if (escape[i].c==car) if (car!='"' && car!=' ') break;
      }
      if (escape[i].c){ /* on a trouvé un caractère à échapper */
	ligne[pligne]='&';
	strcpy(ligne+pligne+1,escape[i].code);
	pligne+=strlen(escape[i].code)+2;
	ligne[pligne-1]=';';
      }
      else{
	/* Ce n'est pas un caractère à coder spécialement: */
	/*   regardons si c'est _lt_, _gt_, ou _und_ */
	if (car=='_'){
	  if (!strncmp(s+in,"_lt_",4)){
	    in+=3;car='<';
	  }else if (!strncmp(s+in,"_gt_",4)){
	    in+=3;car='>';
	  }else if (!strncmp(s+in,"_und_",5)){
	    in+=4;car='_';
	  }
	}
	ligne[pligne++]=car;
      }
    }
    in++;
    if (pligne > longueur - 10){
      ligne=realloc(ligne,longueur=longueur+LONGUEUR_LIGNE);
      if (!ligne) erreur("recodeHTML(): pas assez de mémoire");
    }
  }
  ligne[pligne]='\0';
  return ligne;
}

void nettoiechaine(void){ /* si a_decode, traduit les codes HTML de chaine;
			   * de toute façon enlève le > final et les \n */
  char *pchaine=chaine,
    *p2chaine,code[40];
  int i,p2;
  char c;
  
  /* vérifie qu'on a bien <... > ou &lt;...&gt; */ 
  /* non non, je ne vérifie pas, car Netscape Composer fait
   * presque toujours des &gt;.....>
   * C'est laid, mais Netscape Composer le fait et je l'utilise */
  //  if (a_decoder && chaine[strlen(chaine)-1]=='>')
  //    warning("commande \"<%s\" en HTML se termine par >",
  //	    fonction);
  //  if ((!a_decoder) && chaine[strlen(chaine)-1]!='>')
  //    warning("Attention: commande \"<%s\" en ASCII ne se termine pas par >\n",
  //	    fonction);
  
  /* décode les échappements de liens %xx */
  if (a_decoder_link){
    // remplacement des "+" par des espaces " "
    for(pchaine=chaine;pchaine;pchaine=strchr(pchaine,'+')) *pchaine = ' ';
    // plus remplacement des %xx par ce qu'il faut
    for(pchaine=chaine;pchaine;pchaine=strchr(pchaine,'%')){
      if (strchr("0123456789abcdefABCEDF",pchaine[1]))
	if (strchr("0123456789abcdefABCEDF",pchaine[2])){
	  sscanf(pchaine+1,"%2X",&i);
	  *pchaine=i;
	  strcpy(pchaine+1,pchaine+3);
	}
      pchaine++;
      a_decoder=0;
    }
  }
  
  /* décode les échappements HTML, sauf si déjà codage de type "liens" */
  else a_decoder=1; /* ON MET TOUJOURS À DÉCODER, C'EST ENCORE LE PLUS PRATIQUE */
  if (a_decoder) while ((pchaine=strchr(pchaine,'&'))){
    p2chaine=strchr(pchaine,';');
    if ((!p2chaine) || (p2chaine-pchaine)>=39){ /* pas de ; ou trop long*/
      pchaine++;
      continue;
    }
    memmove(code,pchaine+1,p2chaine-pchaine-1);
    code[p2chaine-pchaine-1]='\0';
    for(i=0;escape[i].c;i++)
      if (!strcmp(code,escape[i].code)){
	*pchaine=escape[i].c;
	strcpy(pchaine+1,p2chaine+1);
	break;
      }
    pchaine++;
  }
  
  /* remplace les '\n' par ' ' */
  for (i=0;chaine[i];i++) if (chaine[i]=='\n') chaine[i]=' ';
  
  /* on devrait avoir un '>' à la fin, et on l'enlève, ou sinon on signale l'erreur (fatale)*/
  i=strlen(chaine)-1;
  if (chaine[i]!='>') {
    if (i>=3 && !strcmp(chaine+i-3,"&gt;")) chaine[i-3]='\0';
    else {
      erreur("La commande <%s ne se termine pas par >",fonction);
    }
  }
  chaine[i]='\0';

  p2chaine=monalloc(longueur=LONGUEUR_LIGNE);
  p2=0;
  for(pchaine=chaine;*pchaine;pchaine++){
    c=*pchaine;
    if (c=='_'){
      if ((!strncmp(pchaine,"_lt_",4)) ||
	  (!strncmp(pchaine,"_und_",5))||
	  (!strncmp(pchaine,"_gt_",4)))
	{strcpy(code,"_und_");c='\0';}
    }
    else if (c=='<') {strcpy(code,"_lt_");c='\0';}    
    else if (c=='>') {strcpy(code,"_gt_");c='\0';}
    if (c) p2chaine[p2++]=c;
    else{
      strcpy(p2chaine+p2,code);
      p2+=strlen(code);
    }
    if (p2 > longueur - 10){
      p2chaine=realloc(p2chaine,longueur=longueur+LONGUEUR_LIGNE);
      if (!p2chaine) erreur("nettoiechaine(): pas assez de mémoire");
    }
  }
  p2chaine[p2]='\0';
  free(chaine);
  chaine=p2chaine;
}


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() )*/
  int c,cmin,premiercar;
  int i;
  int html;
  premiercar=c=mongetc();
  if (premiercar=='&'){
    stocke(); /* c'est peut-être le début de &lt; */
    i=0;
    if (mongetc()=='l')
      if (mongetc()=='t')
	if (mongetc()==';') i=1;
    if (!i) {
      destocke(); return c; /* désolé, c'était une erreur */
    }
    a_decoder=1; /* ça démarre par &lt;, c'est donc du HTML */
    a_decoder_link=0;
  }
  else if (premiercar=='%'){
    stocke(); /* c'est peut-être le début de &3C; */
    i=0;
    if (mongetc()=='3')
      if (strchr("cC",mongetc())) i=1;
    if (!i) {
      destocke(); return c; /* désolé, c'était une erreur */
    }
    a_decoder=0;
    a_decoder_link=1;  /* ça démarre par %3C, c'est donc du codage de liens */
  }
  else if (premiercar=='<') {
    stocke();
    a_decoder=a_decoder_link=0; /* ça démarre par <, c'est donc du ASCII */
  }
  else return c; /* OK, c'est un caractère qui ne pose pas de question */
  /* si on est là, c'est qu'on a vu "<" ou "&lt;" ou %3C, et on stocke */
  /* on lit le nom de la fonction*/
  for (i=0;i<29;i++){
    c=mongetc();
    if (i==0) 
      while (c==' ') c=mongetc(); /* on enlève les espaces après '<' */
    cmin=tolower(c);
    if (c!='/'&&(cmin<'a' || cmin>'z')) break; /*  '/' et minuscules */
    fonction[i]=cmin; /* en minuscules SVP */
  }
  fonction[i]='\0';
  /* est-ce que ça correspond à une fonction? */
  for(i=0;;i++){
    if (!listefonctions[i]){ /* on arrive sur NULL, ça ne correspond pas*/
      destocke();
      return premiercar;
    }
    if (!strcmp(listefonctions[i],fonction)){
      /* on a trouvé une fonction, mais attention, car si c'est <BODY> ou
       * </BODY> et qu'on est dans le fichier principal, il faut la laisser
       * (ainsi que si on est dans un <REINCLUDE> */
      /* si ce n'est pas "body" ni "/body", ça va, je l'accepte */
      if ((strcmp(fonction,"body") && strcmp(fonction,"/body"))) break;
      /* si c'est dans un <REINCLUDE>, je n'accepte que </body> */
      if (flag_reinclude){
	if (!strcmp(fonction,"/body")) break;
      }
      /* sinon, hors du fichier principal, j'accepte <body> et </body> */
      else if (fichier_courant->pere) break;
      /* autres cas: je l'ignore */
    }
  }
  /* OK, c'est donc la fonction i */
  finstocke(); /* on élimine donc ce qu'on a stocké '<fonction#" */
  chaine=monalloc((longueur=LONGUEUR_LIGNE));
  pchaine=0;
  html=0; /* on n'est pas dans une balise HTML */
  while(1){
    if (c==EOF) erreur("EOF rencontré dans l'argument de <%s",fonction);
    chaine[pchaine++]=c;
    if (pchaine>=longueur-3){
      chaine=realloc(chaine,longueur=longueur+LONGUEUR_LIGNE);
      if (!chaine) erreur("decode(): pas assez de mémoire pour lire "
			 "l'argument de <%s",fonction);
    }
    if (c=='<') html=1; /* on rentre dans une balise HTML*/
    if (c=='>'){
      if (html) html=0; /* on sort de la balise HTML */
      else break; /* fin de la commande prehtml */
//    if (chaine[pchaine-1]=='>') break;
    }
    if (pchaine>=4 && a_decoder) if (!strncasecmp(chaine+pchaine-4,"&gt;",4)) 
      break; /* la commande prehtml peut également se terminer ainsi */
    if (pchaine>=3 && a_decoder_link) if (!strncasecmp(chaine+pchaine-3,"%3e",3))
      break;
    c=mongetc();
  }
  chaine[pchaine]=0;
  nettoiechaine();
  //printf("Fonction (codage \"%s\") <%s> avec l'argument '%s'\n",(a_decoder?"HTML":(a_decoder_link?"lien":"ASCII")),fonction,chaine);
  return EST_FONCTION;
  
}
