/*tento program převádí datový soubor ATHELP.HLP (specielní kódování) do formátu HTML v kódování UTF-8
Program dovede zobrazit veškerý obsah manuálu ATHELP s ojedinělými chybami (prosím o jejich nahlášení).

Informace pro sestavení tohoto prográmku byly získány studiem souboru ATHELP.HLP v poznámkovém bloku, hex editoru a porovnáním zobrazení v dosovém prohlížeči.
Program byl laděn a kompilován pod OS. Ubuntu (Linux), může obsahovat platformě závislý kód, není proto zaručeno, že ho lze bez úprav zkompilovat a spustit pod jiným OS, vzhledem k jednoduchosti programu však nebude problém provést případné úpravy.
Načtení celého souboru do dynamycky alokované paměti je jistě neefektivní a v tomto případě zbytečná věc (prakticky by stačil bufer na jeden řádek), nicméně kostru programu jsem měl z jiného projektu, tak jsem si ušetřil trochu práce a hlavně si zopakoval práci s dynamyckou pamětí, ale i tak přeložení pomocí gcc a následný běh programu trvá kratší dobu, než např. uložení tohoto zdrojáku v editoru gedit (cca o 1s) a než načtění výsledného dokumentu ve firefoxu (cca o 5s), ani nemluvě o tom, že firefox s načteným dokumentem zabíra v paměti (dle programu top) okolo 37MB, což také o něčem vypovídá.
Použítí programu je pouze na vlastní nebezpečí, autor nenese žádnou zodpovědnost za případné škody na HW, SW, tělesné, či duševní (zejména při pohledu na kód).

Případné náměty, či připomínky zasílejte na zmijak412@centrum.cz
*/
#define _GNU_SOURCE
#include <stdio.h>

FILE *fr, *fw;
const int prevodni_specTAB[]={
//0x0,     0x01, 0x02,   0x03,   0x04,  0x05, 0x06, 0x07, 0x08,   0x09,   0x0A,   0x0B,   0x0C, 0x0D,   0x0E, 0x0F,
  0x25C4,  0xB1, 0x2564, 0x2592, 0x17E, 0x70, 0x50, 0x30, 0x25BA, 0x2261, 0x2568, 0x2591, 0xC9, 0x2302, 0x5F, 0x3F,

//0x10,   0x11, 0x12,   0x13,   0x14,  0x15, 0x16, 0x17, 0x18,   0x19,   0x1A,   0x1B,   0x1C,  0x1D, 0x1E, 0x1F,
  0x25BC, 0x11, 0x2580, 0x2510, 0x165, 0x15, 0x5E, 0x3E, 0x25B2, 0x25A0, 0x2590, 0x255B, 0x158, 0x7D, 0x5D, 0x3D,

//0x20,   0x21, 0x22,   0x23,   0x24, 0x25, 0x26, 0x27, 0x28,   0x29,   0x2A,   0x2B,   0x2C,  0x2D, 0x2E, 0x2F,
  0x2194, 0xB2, 0x258C, 0x255C, 0xDD, 0x7C, 0x5C, 0x3C, 0x221F, 0x207F, 0x2584, 0x255D, 0x13D, 0x7B, 0x5B, 0x3B,

//0x30, 0x31,   0x32,   0x33,   0x34,  0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,   0x3B,   0x3C, 0x3D, 0x3E, 0x3F,
  0x30, 0x221A, 0x2588, 0x2557, 0x160, 0x7A, 0x5A, 0x3A, 0x38, 0xB7, 0x250C, 0x2551, 0xDC, 0x79, 0x59, 0x39,

//0x40,   0x41,   0x42,   0x43,   0x44, 0x45, 0x46, 0x47, 0x48, 0x49,   0x4A, 0x4B,   0x4C,   0x4D, 0x4E, 0x4F,
  0x2193, 0x2219, 0x2518, 0x2563, 0xD6, 0xFD, 0x78, 0x58, 0x38, 0x2191, 0xB0, 0x256A, 0x2555, 0x67, 0x47, 0x27,

//0x50,   0x51,  0x52,   0x53, 0x54,  0x55, 0x56, 0x57, 0x58,   0x59, 0x5A,   0x5B,  0x5C,  0x5D, 0x5E, 0x5F,
  0x2022, 0x3C4, 0x255F, 0xD4, 0x10D, 0x66, 0x46, 0x26, 0x2660, 0xB5, 0x255E, 0x16E, 0x164, 0x65, 0x45, 0x25,

//0x60,   0x61,  0x62,   0x63,  0x64,  0x65, 0x66, 0x67, 0x68,   0x69,  0x6A,   0x6B,  0x6C, 0x6D, 0x6E, 0x6F,
  0x2663, 0x3C3, 0x253C, 0x147, 0x10E, 0x64, 0x44, 0x24, 0x2666, 0x3A3, 0x2500, 0x148, 0xE4, 0x63, 0x43, 0x23,

//0x70,   0x71,  0x72,   0x73, 0x74,  0x75, 0x76, 0x77, 0x78,   0x79,  0x7A,   0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
  0x2665, 0x3C0, 0x251C, 0xFA, 0x10F, 0x62, 0x42, 0x22, 0x263B, 0x393, 0x252C, 0xF3, 0xE9, 0x61, 0x41, 0x21,

//0x80,   0x81, 0x82,   0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,  0x8A,   0x8B, 0x8C,  0x8D, 0x8E, 0x8F,
  0x263A, 0xDF, 0x2534, 0xED, 0xFC, 0x60, 0x40, 0x20, 0x88, 0x3B1, 0x2514, 0xE1, 0x10C, 0x6F, 0x4F, 0x2F,

//0x90,   0x91,   0x92,   0x93, 0x94, 0x95, 0x96, 0x97, 0x98,   0x99,  0x9A,   0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
  0x263C, 0x2229, 0x2567, 0xBB, 0xC1, 0x6E, 0x4E, 0x2E, 0x266B, 0x3B5, 0x256C, 0xAB, 0xC4, 0x6D, 0x4D, 0x2D,

//0xA0, 0xA1,  0xA2,   0xA3, 0xA4,  0xA5, 0xA6, 0xA7, 0xA8,   0xA9,   0xAA,   0xAB, 0xAC,  0xAD, 0xAE, 0xAF,
  0xA0, 0x3C6, 0x2550, 0xA1, 0x13A, 0x6C, 0x4C, 0x2C, 0x2640, 0x221E, 0x2560, 0xBC, 0x13E, 0x6B, 0x4B, 0x2B,

//0xB0,   0xB1,  0xB2,   0xB3,  0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9,  0xBA,   0xBB,  0xBC,  0xBD, 0xBE, 0xBF,
  0x2642, 0x3B4, 0x2566, 0x154, 0xCD, 0x6a, 0x4A, 0x2A, 0xB8, 0x3A9, 0x2569, 0x155, 0x139, 0x69, 0x49, 0x29,

//0xC0, 0xC1,  0xC2,   0xC3,  0xC4,  0xC5, 0xC6, 0xC7, 0xC8,   0xC9,  0xCA,   0xCB,  0xCC,  0xCD, 0xCE, 0xCF,
  0xC0, 0x398, 0x2554, 0x159, 0x11A, 0x68, 0x48, 0x28, 0x25D8, 0x3A6, 0x255A, 0x161, 0x11B, 0x77, 0x57, 0x37,

//0xD0,   0xD1,   0xD2,   0xD3,   0xD4, 0xD5, 0xD6, 0xD7, 0xD8,   0xD9, 0xDA,   0xDB,   0xDC,  0xDD, 0xDE, 0xDF,
  0x21A8, 0x2248, 0x256B, 0x2556, 0xDA, 0x76, 0x56, 0x36, 0x25AC, 0xF7, 0x2553, 0x2562, 0x16F, 0x75, 0x55, 0x35,

//0xE0, 0xE1,   0xE2,   0xE3,   0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,   0xEA,   0xEB,   0xEC, 0xED, 0xEE, 0xEF,
  0xA7, 0x2321, 0x2552, 0x2561, 0xD3, 0x74, 0x54, 0x34, 0xB6, 0x2320, 0x2558, 0x2524, 0xF6, 0x73, 0x53, 0x33,

//0xF0,   0xF1,   0xF2,   0xF3,   0xF4, 0xF5, 0xF6, 0xF7, 0xF8,   0xF9,   0xFA,   0xFB,   0xFC,  0xFD, 0xFE, 0xFF
  0x203C, 0x2264, 0x2559, 0x2502, 0xF4, 0x72, 0x52, 0x32, 0x2195, 0x2265, 0x2565, 0x2593, 0x17D, 0x71, 0x51, 0x31
};

unsigned char buf[8];
typedef int znak;
typedef znak * radek;
radek aktualni_radek=NULL;
radek *p_pole_radku=NULL;
unsigned int pocetradku=0;

size_t zapsano;

int generator_utf8(unsigned int utfznk, unsigned char *buf){//fce vraci pocet byte utf8 znaku, ulozeneho do buf
int n=0;
 if(utfznk<128){
  n=1;
  buf[0]=(unsigned char)utfznk&0x7f;
 }
 else if(utfznk<2048){
  n=2;
  buf[1]=(unsigned char)(utfznk&0x3f)|0x80;
  buf[0]=(unsigned char)((utfznk>>6)&0x1f)|0xc0;
 }
 else if(utfznk<65535){
  n=3;
  buf[2]=(unsigned char)(utfznk&0x3f)|0x80;
  buf[1]=(unsigned char)((utfznk>>6)&0x3f)|0x80;
  buf[0]=(unsigned char)((utfznk>>12)&0x0f)|0xe0;
 }
return n;
}

int spec_to_utf8(znak c, unsigned char *buf){
int n=0;
unsigned int utfznk;
utfznk = (unsigned int)prevodni_specTAB[c];
if(c!=prevodni_specTAB[c])n=generator_utf8(utfznk, buf);
else if(c==0xF4)n=generator_utf8(utfznk, buf); 
// else n=snprintf(buf, 8* sizeof(unsigned char), "! %X !",c);//zobraz znaky, které nejsou v tabulce
return n;
}

int zobraz_znak(znak c){
int n;
if((c>=0)&&(c<256)){
 n=spec_to_utf8(c, buf);
 fwrite(buf, n, 1, fw);
}

return 0;
}

int vypis_vse(radek *p_pole_radku, unsigned int pocetradku){
unsigned int i,j,n,stavr,stavs,odkaz;
znak c,d;
stavs=0;
for(i=0;i<pocetradku;i++){
j=0;
stavr=0;
 do{
  c=(p_pole_radku[i])[j++];
   if(c==0xA0)stavr=3;//1byte ukonceni radku, ma absolutni prednost pred ostatnimi stavy
  switch(stavr){
   case 0:{//novy radek
     stavr=2;
     if(c==0x37){//dvojtecka na zacatku radku (navesti)
       if(stavs==0){
        stavs=1;
        fputs("<a name=\"" ,fw);
        stavr=1;
       }
       else{ 
        stavs=0;
        break;
       }
      }
      else if(c==0x16)stavr=8;
     }     
   case 2: 
     if(stavr==2){
      if(c==0x15){//zacatek odkazu
       stavr=5;
       n=j;//uloz pozici zacatku odkazu
       fputs(" <a href=\"#", fw);
      }
      else if(stavs==1) zobraz_znak(c);
     }
    break;
   case 1:
     zobraz_znak(c);
     if((p_pole_radku[i])[j]==0xA0){
      fputs("\"></a>", fw);
      stavr=2;
     }
    break;
   case 3: 
     if(c==0xB8)stavr=4;
    break;
   case 4: 
     if(c==0){
      fputs("\n" ,fw);
      stavr=0;
     }
    break;
   case 5: {
     if(c==0x15){//konec vyditelne casti odkazu
      fputs("\">", fw);
      for(;n<(j-1);n++)zobraz_znak((p_pole_radku[i])[n]);//vypsani textu odkazu mezi <a> </a>
      stavr=6;
      odkaz=1;
     }
     else zobraz_znak(c);//vykresluj text odkazu
    }
    break;
   case 6: {//fprintf(fw, "!%X!",c);//odkomentováním se zobrazí skrytý obsah odkazu
      odkaz++;
      if(odkaz>4){//neviditelna cast odkazu(data) ma 4byte 
        d=prevodni_specTAB[((p_pole_radku[i])[j])];
       if((d<0x41||d>0x5A)&&(d<0x61||d>0x7A)&&(d!=0x16F)){//rozsah nevhodných znaků pro přilepení k odkazu
        stavr=2;
        fputs("</a> ", fw);
       }
       else stavr=7;
      }
    }
    break;
   case 7:{
     stavr=2;
     zobraz_znak(c);
     fputs("</a> ", fw);
    }
    break;
   case 8:{
     fputs("<FONT SIZE=+1 color=\"red\"><h2>", fw);
     zobraz_znak(c);
     stavr=9;
    }
    break;
   case 9:{
     zobraz_znak(c);
     if((p_pole_radku[i])[j]==0xA0){
      stavr=2;
      fputs("</h2></FONT>", fw);
      }
    }
  }
 }while(stavr>0);
}
return 0;
}

int uvolni_pamet(radek *p_pole_radku, unsigned int pocetradku){
unsigned int i;
for(i=0;i<pocetradku;i++)free(p_pole_radku[i]); //uvolni pamět řádku
return 0;
}

int main(void){
fr = fopen("ATHELP.HLP", "r");
unsigned int n,i=0;
unsigned int znakuvradku=0;
znak c;

do{
 i++;
 c = getc(fr);
zapis_znak:
 if(znakuvradku==0){
  aktualni_radek=malloc(1 * sizeof(c));
  znakuvradku++;
 }
 else{
  aktualni_radek=realloc(aktualni_radek, sizeof(c) * (++znakuvradku));
 }
 aktualni_radek[znakuvradku - 1]=c;
 if((aktualni_radek[znakuvradku - 1]==0xB8)&&(aktualni_radek[znakuvradku - 2]==0xA0)){//konec radku A0 B8
  c=0;
  goto zapis_znak;
 }

 if((aktualni_radek[znakuvradku - 1]==0)&&(aktualni_radek[znakuvradku - 2]==0xB8)){
  if(pocetradku==0){
   p_pole_radku=malloc(1 * sizeof(radek));
   pocetradku++;
  }
  else{
   p_pole_radku=realloc(p_pole_radku, sizeof(radek) * (++pocetradku));
  }
  p_pole_radku[pocetradku - 1]=aktualni_radek;
  aktualni_radek=NULL;
  znakuvradku=0;
 }
}while(c!=EOF);
//}while(i<50000);//omezení velikosti na 50000 znaků

fclose(fr);
fw = fopen("athelp.htm", "wb");

fputs("<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<BODY>\n<PRE>\n" ,fw); //HTML hlavička
vypis_vse(p_pole_radku, pocetradku);

fputs("</PRE>\n</BODY>" ,fw);
uvolni_pamet(p_pole_radku,pocetradku);
fclose(fw);
}

