#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "databaze.h"


/* definice znamych prikazu */
#define CMD_COUNT 11
#define PRM_COUNT 9

tStr commands[CMD_COUNT] = { "EXIT",  "CLOSE", "OPEN", "IMPORT", "CREATE", 
                             "SAVE", "EXPORT",  "ADD", "DELETE",   "ECHO",
                            "PAUSE"};

tStr parameters[PRM_COUNT] = { "CSV", "HTML", "COLUMN", "ROW", "NAME", 
                              "TYPE", "SIZE", "FALSE", "TRUE"};


/* ============================================================== */
/* IMPLEMENTACE FUNKCI                                            */
/* ============================================================== */

/* -------------------------------------------------------------- */
/* prevede retezec na velka pismena                               */

void uppercase(char *_t) {
    char *start;
    int i, l;
    l = strlen(_t);
    start = _t;
    for (i = 0; i < l; *start = toupper(*start), start++, i++);
    return;
}
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* porovna dva retezce. vraci 0, jsou-li shodne.                  */

int porovnej(char *s1, char *s2) {
    int _res;
    char *S1[1024], *S2[1024];
    strcpy((char*)S1, s1);
    strcpy((char*)S2, s2);
    uppercase((char*)S1);
    uppercase((char*)S2);
    _res = strcoll((char*)S1, (char*)S2);
    return _res;
}
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* funkce slouzi k vytvoreni prazdne databaze                     */
/* vraci ukazatel na alokovanou pamet                             */

tUkDtb nova_dtb() {
    tUkDtb UkDtb;
    /* alokace pameti pro databazi */
    UkDtb = (tUkDtb)malloc(sizeof(tUkDtb));
    /* pokud se pamet nepovedlo alokovat, konec */
    if (UkDtb == NULL ) return UkDtb;
    /* alokace pameti pro zahlavi databaze */
    UkDtb -> UkDtbHeader = (tUkDtbHeader)malloc(sizeof(tDtbHeader));
    /* v pripade, ze se pamet povedlo alokovat */
    /* nastavi pocet sloupcu a radku na 0 */
    if (UkDtb -> UkDtbHeader != NULL ) {
        UkDtb -> UkDtbHeader -> pocet = 0;
        UkDtb -> UkDtbHeader -> pocetPolozek = 0;
        /* ukazatel na prvni polozku je tez NULL */
        UkDtb -> Polozky = NULL;        
    }        
    return UkDtb;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* funkce slouzi k vytvoreni prazdne databaze                     */
/* vraci ukazatel na alokovanou pamet                             */

tUkDtb smaz_dtb(tUkDtb UkDtb) {
    /* prazdnou databazi nema cenu rusit, ze? */
    if (UkDtb == NULL ) return UkDtb;
    /* nejdrive se zrusi vsechny radky */
    while (UkDtb -> UkDtbHeader -> pocetPolozek > 0) smaz_radek(UkDtb, UkDtb -> Polozky);
    /* nyni se uvolni pamet alokovana pro zahlavi */
    free(UkDtb -> UkDtbHeader);
    /* a nakonec samotna databaze */
    free(UkDtb);
    UkDtb = NULL;
    return UkDtb;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* funkce "oreze" databazi na nejmensi nutnou velikost (tzn.      */
/* zmensi velikost vsech sloupcu na delku nejdelsiho obsahu bunky */
/* v danem sloupci).                                              */

void zmensi_dtb(tUkDtb UkDtb) {
    int max_size[MAX_POCET_SLOUPCU];
    tUkPolozka Polozka;
    int i, j, s, m;
    Polozka = UkDtb -> Polozky;
    s = UkDtb -> UkDtbHeader -> pocet;
    for (j = 0; j < s; j++) max_size[j] = 0;
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocetPolozek; i++) {
        for (j = 0; j < s; j++)
            if ((m = strlen((char*)Polozka -> UkSloupec[j])) > max_size[j]) max_size[j] = m;
        Polozka = Polozka -> Next;
    }
    for (j = 0; j < s; j++) zmen_velikost(UkDtb, j, max_size[j]);
    return;
}
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* prida do "hlavicky" databaze novy sloupec                      */
/* pokud jiz existuje, nebo pro novy sloupec neni misto, vraci -1 */

int vytvor_sloupec(tUkDtb UkDtb, char *nazev, int typ, int velikost) {
    int i, j;
    int index;
    tUkPolozka Polozka;
    index = UkDtb -> UkDtbHeader -> pocet;
    /* jsou-li jiz vsechny sloupce obsazeny, konec s chybou */
    if (index >= MAX_POCET_SLOUPCU) return -1;
    /* pokud sloupec s timto nazvem jiz existuje, taktez konec */
    if (hledej_sloupec(UkDtb, nazev) != -1) return -1;
    /* zkopiruje nazev sloupce do zahlavi databaze */
    strcpy((char*)UkDtb -> UkDtbHeader -> nazev[index], nazev);
    /* nastavi typ a velikost sloupce */
    UkDtb -> UkDtbHeader -> typ[index] = typ;
    UkDtb -> UkDtbHeader -> velikost[index] = velikost;
    /* a pro vsechny radky databaze alokuje pamet pro novy sloupec */
    Polozka = UkDtb -> Polozky;
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocetPolozek; i++) {
        /* pokud nelze celou pamet alokovat, uvolni tu cast, kterou */
        /* se alokovat povedlo a konec s chybou */
        if ((Polozka -> UkSloupec[index] = (char*)calloc(velikost+1, sizeof(char))) == NULL) {
            Polozka = UkDtb -> Polozky;
            for (j = 0;j < i; free(Polozka -> UkSloupec[index]), Polozka -> UkSloupec[index] = NULL, j++);
            return -1;
        }    
        /* vsechny nove vytvorene sloupce se vyprazdni (obsah = "") */
        Polozka -> UkSloupec[index][0] = '\0';
        Polozka = Polozka -> Next;
    }
    /* v hlavicce databaze se zvetsi pocet sloupcu */
    UkDtb -> UkDtbHeader -> pocet++;
    return 0;
}   
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* zmeni sirku sloupce. pokud neexistuje nebo neni misto, vraci -1*/

int zmen_velikost(tUkDtb UkDtb, int index, int velikost) {
    int i, j;
    tUkPolozka Polozka;
    tSloupce UkSloupec;
    /* je-li index mimo rozsah, konec s chybou */
    if ((index < 0) || (index >= UkDtb -> UkDtbHeader -> pocet)) return -1;
    /* je-li nova velikost shodna se stavajici, neni co resit */
    if (velikost == UkDtb -> UkDtbHeader -> velikost[index]) return 0;
    /* pro vsechny radky databaze realokuje pamet pro novy sloupec */
    Polozka = UkDtb -> Polozky;
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocetPolozek; i++) {
        if ((UkSloupec = (char*)calloc(velikost+1, sizeof(char))) == NULL) {
/* mozna by nebylo na skodu prealokovat z5 na puvodni velikost */
/*            Polozka = UkDtb -> Polozky;
            for (j = 0; j < i; free(Polozka -> UkSloupec[index]), Polozka -> UkSloupec[index] = NULL, j++);*/
            return -1;
        }    
        strcpy(UkSloupec, Polozka -> UkSloupec[index]);
        free(Polozka -> UkSloupec[index]);
        Polozka -> UkSloupec[index] = UkSloupec;
        Polozka = Polozka -> Next;
    }
    /* nastavi novou velikost sloupce */
    UkDtb -> UkDtbHeader -> velikost[index] = velikost;
    return 0;
}   
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* vytvori novy radek databaze, vynuluje hodnoty vsech sloupcu    */
/* a vrati na nej ukazatel. pokud se nepodari alokovat misto      */
/* v pameti, fce vrati NULL                                       */

tUkPolozka vytvor_radek(tUkDtb UkDtb) {
    int i;
    tUkPolozka New;
    /* alokuje v pameti mislo pro novy radek */
    New = (tUkPolozka)malloc(sizeof(tPolozka));
    /* v pripade chyby konec */
    if (New == NULL) return NULL;
    /* pro vsechny sloupce alokuje misto v pameti a nastavi obsah */
    /* na prazdno (tj. "") */
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocet; i++) {
        /* jestli se nepovede alokovat pamet pro vsechny sloupce */
        /* pak uvolni tu, kterou se alokovat povedlo a konec */
        if ((New -> UkSloupec[i] = (char*)calloc(UkDtb -> UkDtbHeader -> velikost[i]+1, sizeof(char))) == NULL) {
            for (;i > 0; free(New -> UkSloupec[--i]));
            free(New);
            return NULL;
        }    
        /* vymazani obsahu */
        New -> UkSloupec[i][0] = '\0';
    }
    /* v hlavicce dtb se zvetsi pocet radku */
    UkDtb -> UkDtbHeader -> pocetPolozek++;
    /* v pripade, ze jiz nejaky radek existoval, nastavi ukazatel
       na nej, jakozto na pristi radek (provadi InsertFirst) */
    if (UkDtb -> Polozky != NULL) UkDtb -> Polozky -> Previous = New;
    /* ukazatel na predchozi radek musi byt samozrejme nulovy -
       vlozili jsme prvni polozku */
    New -> Previous = NULL;
    /* nastavi ukazatel pristi polozky na predchozi polozku */
    New -> Next = UkDtb -> Polozky;
    /* a konecne nastavi ukazatel na prvni polozku databaze
       na nove vytvorenou */
    UkDtb -> Polozky = New;
    return New;
}
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* vrati pocet radku v databazi (nulu, je-li prazdna a -1, pokud  */
/* neexistuje)                                                    */

int pocet_radku(tUkDtb UkDtb) {
    /* pokud databaze neexistuje (ukazatel je NULL), vrati -1 */
    if (UkDtb == NULL) return -1;
    /* precte pocet radku ze zahlavi databaze a vrati jej */
    return UkDtb -> UkDtbHeader -> pocetPolozek;
}
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* zapise hodnotu konkretni bunky. je-li index mimo platny rozsah,*/
/* nedela nic. je-li delka hodnoty vetsi, nez velikost sloupce,   */
/* zvetsi ho na novou velikost                                    */

void zapis_polozku(tUkDtb UkDtb, tUkPolozka Polozka, int index, char *hodnota) {
    int m;
    /* je-li mimo rozsah, konec */
    if ((index < 0) || (index >= UkDtb -> UkDtbHeader -> pocet)) return;
    /* ... jinak zapis hodnotu */
    /* (ale napred zkontroluj delku a pripadne ji uprav) */
    if ((m = strlen((char*)hodnota)) > UkDtb -> UkDtbHeader -> velikost[index])
        zmen_velikost(UkDtb, index, m);
    strcpy(Polozka -> UkSloupec[index], hodnota);
    return;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* cte hodnotu konkretni bunky.                                   */
/* neexistuje-li, vraci NULL                                      */

char *cti_polozku(tUkDtb UkDtb, tUkPolozka Polozka, int index) {
    /* je-li hledany sloupec mimo platny rozsah (tzn. mimo
       interval <0, pocet-1>, pak konec */
    if ((index < 0) || (index >= UkDtb -> UkDtbHeader -> pocet)) return NULL;
    /* vrati ukazatel na obsah sloupce */
    return Polozka -> UkSloupec[index];
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* vrati datovy typ sloupce.                                      */
/* v pripade neexistujiciho sloupce vrati -1                      */

int cti_typ(tUkDtb UkDtb, int index) {
    /* je-li mimo rozsah, konec */
    if ((index < 0) || (index >= UkDtb -> UkDtbHeader -> pocet)) return -1;
    /* precte typ sloupce ze zahlavi */
    else return UkDtb -> UkDtbHeader -> typ[index];
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* vrati velikost sloupce.                                        */
/* v pripade neexistujiciho sloupce vrati -1                      */

int cti_velikost(tUkDtb UkDtb, int index) {
    /* je-li mimo rozsah, konec */
    if ((index < 0) || (index >= UkDtb -> UkDtbHeader -> pocet)) return -1;
    /* precte velikost sloupce ze zahlavi */
    else return UkDtb -> UkDtbHeader -> velikost[index];
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* vraci cislo sloupce s hledanym nazvem                          */
/* pokud neexistuje, vrati -1                                     */

int hledej_sloupec(tUkDtb UkDtb, char *nazev) {
    int index, i;
    char *TXT1[32], *TXT2[32];
    strcpy((char*)TXT2, nazev);
    uppercase((char*)TXT2);
    index = -1;
    i = 0;
    /* opakuj, dokud nenaleznes hledany sloupec nebo neni posledni */
    while ((i < UkDtb -> UkDtbHeader -> pocet) && (index == -1)) {
        /* pokud nalezeno, pak uloz do index cislo sloupce */
        strcpy((char*)TXT1, (char*)UkDtb -> UkDtbHeader -> nazev[i]);
        uppercase((char*)TXT1);
        if (strcoll((char*)TXT1, (char*)TXT2) == 0) index = i;
        i++;
    } 
    /* vrat cislo sloupce */
    return index;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* vraci ukazatel na radek, v nemz ma sloupec [index] hledanou    */
/* hodnotu. Nenajde-li, vraci NULL. start ukazuje na prvni        */
/* polozku, od niz se ma zacit hledat (pokud NULL, zacatek dtb)   */

tUkPolozka hledej_radek(tUkDtb UkDtb, tUkPolozka start, int index, char *hodnota) {
    tUkPolozka Polozka = NULL, i;
    int _r = -1;
    char *TXT1[1024], *TXT2[1024];
    strcpy((char*)TXT2, hodnota);
    uppercase((char*)TXT2);
    /* zacina se od start, pokud je NULL, tak od zacatku dtb */
    if ((i = start) == NULL) i = UkDtb -> Polozky;
    /* opakuj, dokud nenaleznes hledany text, nebo neni posledni
       radek databaze (tzn. ukazatel na dalsi radek = NULL */
    while ((_r != 0) && (i != NULL)) {
        strcpy((char*)TXT1, i -> UkSloupec[index]);
        uppercase((char*)TXT1);
        _r = strcoll((char*)TXT1, (char*)TXT2);
        if (_r != 0) i = i -> Next;
    }
    if (_r == 0) Polozka = i;
    return Polozka;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* odstrani radek, na nejz ukazuje parametr. Vraci ukazatel na    */
/* pristi platny radek. Neni-li zadny, vraci NULL                 */

tUkPolozka smaz_radek(tUkDtb UkDtb, tUkPolozka Polozka) {
    tUkPolozka Next;
    int i;
    /* pokud chceme rusit "nic", tak konec */
    if (Polozka == NULL) return NULL;
    /* principem teto funkce je nastavit ukazatele predchoziho
       a dalsiho radku (existuji-li) na dalsi a predchozi a
       dany radek zrusit. Jinymi slovy:
       *    necht mame radky A, B a C a chceme zrusit radek B.
       *    pak ukazatel z radku A na dalsi radek nastavime na C.
       *    ukazatel z radku C na predchozi nastavime na A.
       *    tim radek  B prestal formalne existovat a staci
       *    uz jenom uvolnit pamet, kterou obsazuje */
    /* tady nastavujeme ukazatel predchoziho radku. Pokud je mazany
       radek prvnim, pak misto toho zmenime ukazatel na prvni radek */
    if (Polozka -> Previous != NULL) ((tPolozka*)Polozka -> Previous) -> Next = Polozka -> Next;
    else UkDtb -> Polozky = Polozka -> Next;
    /* pokud radek neni poslednim, pak nastavime ukazatel
       nasledujiciho radku */
    if (Polozka -> Next != NULL) ((tPolozka*)Polozka -> Next) -> Previous = Polozka -> Previous;
    /* zapamatujeme si ukazatel na dalsi radek - vracime ho totiz
       jako vysledek fce */
    Next = Polozka -> Next;
    /* uvolnime pamet vsech sloupcu na danem radku ...*/
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocet; free(Polozka -> UkSloupec[i++]));
    /* ... a ted samotneho radku */
    free(Polozka);
    /* zmensime pocet radku v hlavicce dtb */
    UkDtb -> UkDtbHeader -> pocetPolozek--;
    /* a konec */
    return Next;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* odstrani sloupec, na nejz ukazuje parametr.                    */
/* neexistuje-li, vraci -1                                        */

int smaz_sloupec(tUkDtb UkDtb, int index) {
    tUkPolozka Polozka;
    int i, j;
    /* pokud chceme odstranovat neexistujici sloupec, konec */
    if ((index < 0) || (index >= UkDtb -> UkDtbHeader -> pocet)) return -1;
    /* v cyklu se projdou vsechny radky a u kazdeho z nich se uvolni
       misto alokovane pro dany sloupec */
    Polozka = UkDtb -> Polozky;
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocetPolozek; i++) {
        free(Polozka -> UkSloupec[index]);
        /* veskere sloupce lezici od daneho vpravo (cili mazeme-li
           sloupec 4 a mame dalsi 5, 6 a 7) se posunou doleva
           (takze se ze sloupcu 5, 6 a 7 stanou 4, 5 a 6) */
        for (j = index+1; j < UkDtb -> UkDtbHeader -> pocet; j++)
            Polozka -> UkSloupec[j-1] = Polozka -> UkSloupec[j];
        Polozka -> UkSloupec[j-1] = NULL;
        Polozka = Polozka -> Next;
    }
    /* stejne se musi doleva posunout i nazvy sloupcu v hlavicce */
    for (j = index+1; j < UkDtb -> UkDtbHeader -> pocet; j++) {
        strcpy((char*)UkDtb -> UkDtbHeader -> nazev[j-1], (char*)UkDtb -> UkDtbHeader -> nazev[j]);
        UkDtb -> UkDtbHeader -> typ[j-1] = UkDtb -> UkDtbHeader -> typ[j];
        UkDtb -> UkDtbHeader -> velikost[j-1] = UkDtb -> UkDtbHeader -> velikost[j];
    }
    strcpy((char*)UkDtb -> UkDtbHeader -> nazev[j-1], "");
    /* a zmensi se udaj v hlavicce o poctu sloupcu */
    UkDtb -> UkDtbHeader -> pocet--;
    return 0;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* ulozi celou databazi do souboru. nastane-li chyba, vrati -1    */

int uloz_dtb(tUkDtb UkDtb, char *filename) {
    FILE *soubor;
    size_t ulozeno;
    int i,j;
    tUkPolozka Polozka;
    /* pokusi se vytvorit soubor s pozadovanym jmenem */
    if ((soubor = fopen(filename, "wb")) == NULL) {
        printf("! neotevren %s\n", filename);
        return -1;
    }
    /* zapise hlavicku databaze do souboru */
    ulozeno = fwrite(UkDtb -> UkDtbHeader, 1, sizeof(tDtbHeader), soubor);
    /* nepovedlo-li se, zavre soubor a konec */
    if (ulozeno != sizeof(tDtbHeader)) {
        fclose(soubor);
        return -1;
    }
    /* ... a v cyklu po radcich a sloupcich uklada obsahy
       jednotlivych bunek. */
    Polozka = UkDtb -> Polozky;
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocetPolozek; i++) {
        for (j = 0; j < UkDtb -> UkDtbHeader -> pocet; j++) {
            ulozeno = fwrite(Polozka -> UkSloupec[j], 1, UkDtb -> UkDtbHeader -> velikost[j] * sizeof(char), soubor);
            /* nepodari-li se neco zapsat, zavre soubor
               a skonci chybou */
            if (ulozeno != UkDtb -> UkDtbHeader -> velikost[j] * sizeof(char)) {
                fclose(soubor);
                return -1;
            }
        }    
        Polozka = Polozka -> Next;
    }    
    /* nakonec uzavre soubor */
    fclose(soubor);
    return 0;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* nacte databazi ze souboru a vrati na ni ukazatel.              */
/* nastane-li chyba, vrati NULL                                   */

tUkDtb nacti_dtb(char *filename) {
    tUkDtb UkDtb;
    FILE *soubor;
    size_t nacteno;
    tUkPolozka Polozka;
    int pocetPolozek;
    int i,j;
    /* pokusi se otevrit dany soubor pro cteni (read binary) */
    if ((soubor = fopen(filename, "rb")) == NULL) return NULL;
    /* povedlo-li se, pak vytvori novou databazi ... */
    UkDtb = nova_dtb();
    /* nacte hlavicku */
    nacteno = fread(UkDtb -> UkDtbHeader, 1, sizeof(tDtbHeader), soubor);
    if (nacteno != sizeof(tDtbHeader)) {
        fclose(soubor);
        free(UkDtb);
        return NULL;
    }
    /* ulozi si bokem pocet radku databaze - v hlavicce je musi
       totiz vynulovat a postupne nacitat radky */
    pocetPolozek = UkDtb -> UkDtbHeader -> pocetPolozek;
    UkDtb -> UkDtbHeader -> pocetPolozek = 0;
    /* a tady je nacita */
    for (i = 0; i < pocetPolozek; i++) {
        if ((Polozka = vytvor_radek(UkDtb)) == NULL) {
            fclose(soubor);
            UkDtb = smaz_dtb(UkDtb);
            return NULL;
        }
        for (j = 0; j < UkDtb -> UkDtbHeader -> pocet; j++) {
            /* ... bunku po bunce */
            nacteno = fread(Polozka -> UkSloupec[j], 1, UkDtb -> UkDtbHeader -> velikost[j] * sizeof(char), soubor);
            if (nacteno != UkDtb -> UkDtbHeader -> velikost[j] * sizeof(char)) {
                fclose(soubor);
                UkDtb = smaz_dtb(UkDtb);
                return NULL;
            }
        }    
    }    
    /* nakonec zavre soubor, setridi databazi a skonci */
    fclose(soubor);
    setrid_dtb(UkDtb, 1, 0);
    return UkDtb;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* pripoji databazi ze souboru k existujici                       */
/* nastane-li chyba, vrati -1, jinak pocet pridanych radku.       */

int pripoj_dtb(tUkDtb UkDtb, char *filename, int ignore_column_names) {
    FILE *soubor;
    size_t nacteno;
    tUkPolozka Polozka;
    tUkDtb TmpDtb;
    int pocetPolozek;
    int i,j;
    /* ...nacte soubor do docasne databaze... */
    if ((TmpDtb = nacti_dtb(filename)) == NULL) return -1;
    /* ...slouci docasnou databazi s existujici... */
    /* (a sice napred vytvori v existujici databazi ty sloupce, ktere v ni chybi) */
    /* (a potom provede samotne kopirovani) */
    if (ignore_column_names == 1) {
        if (TmpDtb -> UkDtbHeader -> pocet > UkDtb -> UkDtbHeader -> pocet) {
            for (j = 0; j < UkDtb -> UkDtbHeader -> pocet; j++)
                if (UkDtb -> UkDtbHeader -> velikost[j] < TmpDtb -> UkDtbHeader -> velikost[j])
                    zmen_velikost(UkDtb, j, TmpDtb -> UkDtbHeader -> velikost[j]);
            while (TmpDtb -> UkDtbHeader -> pocet > UkDtb -> UkDtbHeader -> pocet) {
                j = UkDtb -> UkDtbHeader -> pocet;
                vytvor_sloupec(UkDtb, (char*)TmpDtb -> UkDtbHeader -> nazev[j], TmpDtb -> UkDtbHeader -> typ[j], TmpDtb -> UkDtbHeader -> velikost[j]);
            }
        } else for (j = 0; j < TmpDtb -> UkDtbHeader -> pocet; j++)
            if (UkDtb -> UkDtbHeader -> velikost[j] < TmpDtb -> UkDtbHeader -> velikost[j])
                zmen_velikost(UkDtb, j, TmpDtb -> UkDtbHeader -> velikost[j]);
        while (TmpDtb -> UkDtbHeader -> pocetPolozek > 0) {
            Polozka = vytvor_radek(UkDtb);
            for (j = 0; j < TmpDtb -> UkDtbHeader -> pocet; j++)
                zapis_polozku(UkDtb, Polozka, j, (char*)TmpDtb -> Polozky -> UkSloupec[j]);
            smaz_radek(TmpDtb, TmpDtb -> Polozky);
        }
    } else {
        for (j = 0; j < TmpDtb -> UkDtbHeader -> pocet; j++)
            if (hledej_sloupec(UkDtb, (char*)TmpDtb -> UkDtbHeader -> nazev[j]) == -1)
                vytvor_sloupec(UkDtb, (char*)TmpDtb -> UkDtbHeader -> nazev[j], TmpDtb -> UkDtbHeader -> typ[j], TmpDtb -> UkDtbHeader -> velikost[j]);
            else if (UkDtb -> UkDtbHeader -> velikost[hledej_sloupec(UkDtb, (char*)TmpDtb -> UkDtbHeader -> nazev[j])] < TmpDtb -> UkDtbHeader -> velikost[j])
                zmen_velikost(UkDtb, hledej_sloupec(UkDtb, (char*)TmpDtb -> UkDtbHeader -> nazev[j]), TmpDtb -> UkDtbHeader -> velikost[j]);
        while (TmpDtb -> UkDtbHeader -> pocetPolozek > 0) {
            Polozka = vytvor_radek(UkDtb);
            for (j = 0; j < TmpDtb -> UkDtbHeader -> pocet; j++)
                zapis_polozku(UkDtb, Polozka, hledej_sloupec(UkDtb, (char*)TmpDtb -> UkDtbHeader -> nazev[j]), (char*)TmpDtb -> Polozky -> UkSloupec[j]);
            smaz_radek(TmpDtb, TmpDtb -> Polozky);
        }
    }
    /* ...zrusi docasnou databazi, setridi existujici a skonci. */
    smaz_dtb(TmpDtb);
    setrid_dtb(UkDtb, 1, 0);
    return pocetPolozek;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* konecny automat - zpracovava vstup (.CSV soubor) a rozdeluje   */
/* ho na jednotlive polozky (ty jsou na vstupu od sebe oddeleny   */
/* strednikem). Po detekci EOL vola funkci na zpracovani radku.   */

void char_process(char znak, tUkDtb *UkDtb, tFlags *flags, tCmmnd *_strs, int do_comments,
                  char *eos, char *eol, void (*_command)(tCmmnd *_s, tUkDtb *UkDtb, int *cis), int *cislo) {
    char *_znak[2];
    strncpy((char*)_znak, &znak, 2);
    if ((do_comments) && (flags -> comment)) {
        switch (znak) {
            case '*' :
                flags -> comment_end = 1;
                break;
            case '/' :
                if (flags -> comment_end) {
                    flags -> comment_end = 0;
                    flags -> comment = 0;
                    break;
                }
            default:
                flags -> comment_end = 0;
        }
        return;
    }
    if (flags -> string) {
        switch (znak) {
            case '"' :
                if (flags -> string_begin == 0) {
                    flags -> string = 0;
                    break;
                }
            default:
                flags -> string_begin = 0;
                strncat((char*)_strs -> param[_strs -> cnt], (char*)_znak, 1);
        }
        return;
    }
    if (do_comments) 
        if ((flags -> comment_begin == 1) && (znak != '*')) {
            strcat((char*)_strs -> param[_strs -> cnt], "/");
            flags -> comment_begin == 0;
        }
    switch (znak) {
        case '"':
            flags -> string = 1;
            flags -> string_begin = 1;
            break;
        case '/':
            if (do_comments) {
                flags -> comment_begin = 1;
                break;
            }
        case '*':
            if ((do_comments) && (flags -> comment_begin == 1)) {
                flags -> comment_begin = 0;
                flags -> comment = 1;
                break;
            }
        default:
            /* vyhodnoti, zda je znakem ukoncujicim retezec */
            if (strchr(eos, znak) != NULL) {
                if (strchr(" \n", znak) != NULL) {
                    if (strlen(_strs -> param[_strs -> cnt]) > 0) _strs -> param[++_strs -> cnt][0] = '\0';
                } else _strs -> param[++_strs -> cnt][0] = '\0';
                break;
            }
            /* vyhodnoti, zda je znakem ukoncujicim radek */
            if (strchr(eol, znak) != NULL) {
                _strs -> cnt++;
                _command(_strs, UkDtb, cislo);
                break;
            }
            strncat((char*)_strs -> param[_strs -> cnt], (char*)_znak, 1);
            flags -> comment_begin = 0;
    }
    return;
}
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* prida sloupce ze souboru .CSV                                  */

void add_columns(tCmmnd *_strs, tUkDtb UkDtb) {
    int _i;
    for (_i = 0; _i < _strs -> cnt; _i++) {
        vytvor_sloupec(UkDtb, (char*)_strs -> param[_i], 0, 8);
    }
    _strs -> cnt = 0;
    _strs -> param[0][0] = '\0';
    return;
}
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
char *prevod(long num, char *str, int soustava)
{
    char cislice[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
                        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
                        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
                        'U', 'V', 'W', 'X', 'Y', 'Z'};
    if (num == 0) strcpy(str, "0");
    while (num > 0) {
        strcpy(str+1, str);
        str[0] = cislice[num%soustava];
        num /= soustava;
    }
	return str;
}
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* zpracovava radek souboru .CSV                                  */

void add_line(tCmmnd *_strs, tUkDtb UkDtb) {
    int _i;
    char *column[32];
    tUkPolozka Polozka;
    if ((Polozka = vytvor_radek(UkDtb)) != NULL) {
        for (_i = 0; _i < _strs -> cnt; _i++) {
            if (UkDtb -> UkDtbHeader -> pocet <= _i) {
                prevod(_i, (char*)column, 16);
                vytvor_sloupec(UkDtb, (char*)column, 0, 8);
            }
            zapis_polozku(UkDtb, Polozka, _i, (char*)_strs -> param[_i]);
        }
    }
    _strs -> cnt = 0;
    _strs -> param[0][0] = '\0';
    return;
}
/*                                                                */
/* -------------------------------------------------------------- */


    void _delej(tCmmnd *_str, tUkDtb *UDtb, int *prvni) {
        if (prvni) {
            prvni = 0;
            add_columns(_str, *UDtb);
        } else add_line(_str, *UDtb);
        return;
    }


/* -------------------------------------------------------------- */
/* importuje databazi ze souboru ve formatu CSV (text oddeleny    */
/* stredniky) a vrati na ni ukazatel. nastane-li chyba, vrati NULL*/

tUkDtb import_CSV(char *filename, int header) {
    int prvni;
    tUkDtb UkDtb;
    FILE *soubor;
    char *buffer[1024];
    char *start;
    tFlags flags;
    tCmmnd _strs;
    tUkPolozka Polozka;
    int i;

    /* pokusi se otevrit dany soubor pro cteni */
    if ((soubor = fopen(filename, "r")) == NULL) return NULL;
    /* vytvori novou databazi ... */
    if ((UkDtb = nova_dtb()) == NULL) return NULL;
    flags.comment = 0;
    flags.comment_begin = 0;
    flags.comment_end = 0;
    flags.string = 0;
    flags.string_begin = 0;
    _strs.cnt = 0;
    _strs.param[0][0] = '\0';
    /* je-li header = 1, nacte nazvy sloupcu a vytvori je */
    prvni = header;
    /* a pak uz nacita radky */
    while (fgets((char*)buffer, 1024, soubor) != NULL) {
        start = (char*)buffer;
        while(strlen(start) > 0) {
            char_process(*start++, &UkDtb, &flags, &_strs, 0, ";", "\n", _delej, &prvni);
        }
    }
    /* nakonec zavre soubor, setridi databazi a skonci */
    fclose(soubor);
    setrid_dtb(UkDtb, 1, 0);
    return UkDtb;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* exportuje databazi do formatu CSV. nastane-li chyba, vrati -1  */

int export_CSV(tUkDtb UkDtb, char *filename, int header) {
    FILE *soubor;
    int i,j;
    tUkPolozka Polozka;
    /* pokusi se otevrit soubor pro zapis */
    if ((soubor = fopen(filename, "w")) == NULL) return -1;
    /* je-li header = 1, zapise nazvy sloupcu */
    if (header) {
        for (j = 0; j < UkDtb -> UkDtbHeader -> pocet; j++) {
            if (j > 0) fprintf(soubor, ";");
            fprintf(soubor, "%s", UkDtb -> UkDtbHeader -> nazev[j]);
        }    
        fprintf(soubor, "\n");
    }
    /* ... a postupne zapisuje radky databaze */
    Polozka = UkDtb -> Polozky;
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocetPolozek; i++) {
        for (j = 0; j < UkDtb -> UkDtbHeader -> pocet; j++) {
            if (j > 0) fprintf(soubor, ";");
            fprintf(soubor, Polozka -> UkSloupec[j]);
        }    
        fprintf(soubor, "\n");
        Polozka = Polozka -> Next;
    }    
    fclose(soubor);
    return 0;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* exportuje databazi do podoby tabulky ve formatu HTML           */
/* nastane-li chyba, vrati -1                                     */

int export_HTML(tUkDtb UkDtb, char *filename, const char *title) {
    FILE *soubor;
    int i,j;
    tUkPolozka Polozka;
    /* pokusi se otevrit soubor pro zapis */
    if ((soubor = fopen(filename, "w")) == NULL) return -1;
/* pozn. aktualni verze predpoklada kodovani win-1250 */
    /* zapise do souboru HTML hlavicku atd... */
    fprintf(soubor, "<html>\n<head>\n<meta http-equiv=Content-Type content=\"text/html; charset=windows-1250\">\n<meta name=Generator content=\"Databáze %s\">\n<title>", VERZE);
    fprintf(soubor, "%s", title);
    fprintf(soubor, "</title>\n<style>BODY {FONT-FAMILY:  Arial, Helvetica, sans-serif; FONT-SIZE: 10pt; color: black;}\nTD {text-align=center; FONT-SIZE: 10pt;} H3 {text-align : center;} </style></head>\n");
/*    fprintf(soubor, "</title>\n<style>BODY {FONT-FAMILY:  Arial, Helvetica, sans-serif; FONT-SIZE: 10pt; color: black;}\nTD {FONT-SIZE: 10pt;} H3 {text-align : center;} </style></head>\n");*/
    fprintf(soubor, "<body>\n");
    fprintf(soubor, "<H3>%s</H3>", title);
    fprintf(soubor, "<br><br><table border=1 cellspacing=0 cellpadding=0 width=100%% style='border-collapse:collapse'>\n");

    /* tucne zapise nazvy sloupcu */
    fprintf(soubor, "<tr><td></td>");
    for (j = 0; j < UkDtb -> UkDtbHeader -> pocet; j++) {
        fprintf(soubor, "<td><b>");
        fprintf(soubor, "%s", UkDtb -> UkDtbHeader -> nazev[j]);
        fprintf(soubor, "</b></td>");
    }    
    fprintf(soubor, "</tr>\n");

    /* ... a postupne vytvari tabulku z databaze */
    Polozka = UkDtb -> Polozky;
    for (i = 0; i < UkDtb -> UkDtbHeader -> pocetPolozek; i++) {
        if (fmod(i, 2) == 0) fprintf(soubor, "<tr bgcolor=EFEFEF><td>%d</td>", i+1);
        else fprintf(soubor, "<tr bgcolor=FFFFFF><td>%d</td>", i+1);
        for (j = 0; j < UkDtb -> UkDtbHeader -> pocet; j++) {
            fprintf(soubor, "<td>");
            fprintf(soubor, Polozka -> UkSloupec[j]);
            fprintf(soubor, "</td>");
        }    
        fprintf(soubor, "</tr>\n");
        Polozka = Polozka -> Next;
    }    
    /* nakonec ukoncovaci kod...*/
    fprintf(soubor, "</table><br><br><font size=1><p align=right>automaticky generováno systémem Databáze %s</p></font><br></body>\n</html>", VERZE);
    fclose(soubor);
    return 0;
}    
/*                                                                */
/* -------------------------------------------------------------- */


/* -------------------------------------------------------------- */
/* setridi databazi (vzestupne: smer = 1, sestupne: smer = -1)    */
/* trideni probiha podle prvniho sloupce (pri shode pak podle     */
/* druheho, atd.). Je-li from_last = 1, pak se tridi odzadu.      */

void setrid_dtb(tUkDtb UkDtb, int smer, int from_last) {
    /* pokud !nechceme! tridit, pak konec */
    if (smer == 0) return;
    /* a jeste provedeme upravu smeru tak, abychom urcite meli
       bud -1 nebo 1 (se zapornych udelame -1, z kladnych 1) */
    if (smer < 0) smer = -1;
    if (smer > 0) smer = 1;
    /* max - pocet porovnavani v cyklu for */
    /* i - pomocna promenna pro cyklus for */
    /* index - index porovnavaneho sloupce */
    /* zmena - navesti, zda doslo k zamene */
    /* first - prvni porovnavany sloupec */
    /* inc - smer porovnavani sloupcu */
    /* res - vysledek porovnani sloupcu */
    int max, i, index, zmena, first, inc, res;
    tUkPolozka A, B;
    /* tridi se klasickou metoudou BubbleSort se zmensujicim se */
    /* maximalnim indexem */
    max = UkDtb -> UkDtbHeader -> pocetPolozek-1;
    /* podle toho, zda tridime podle prvniho nebo posledniho sloupce,
       nastavime smer a prvni index */
    if (from_last == 0) {inc = 1; first = 0;} else {inc = -1; first = UkDtb -> UkDtbHeader -> pocet-1;};
    /* zmena musi byt 1, aby doslo k prvnimu pruchodu */
    zmena = 1;
    /* cyklus opakovani prochazeni pole, pokud stale neni setridene
       (v predchozim pruchodu doslo k zamene prvku) a stale je co
       prochazet (interval je nenulovy) */
    while ((zmena == 1) && (max > 0)) {
        /* predbezne se nastavi navesti zameny na nulu */
        zmena = 0;
        /* ukazatel se nastavi na zacatek databaze */
        A = UkDtb -> Polozky;
        /* porovnavaji se sousedni radky */
        for (i = 0; i < max; i++) {
            /* nejdrive se porovnaji prvni sloupce. jsou-li shodne,
               pak index se zvysi a dochazi znova k porovnavani az
               do doby, dokud se nenajde rozdil nebo se nenarazi na
               konec radku. je-li from_last = 1, pak naopak */
            index = first;
            while ((index != (first + inc * UkDtb -> UkDtbHeader -> pocet)) && ((res = strcoll(A -> UkSloupec[index], A -> Next -> UkSloupec[index])) == 0)) index+=inc;
            /* vzhledem k typu trideni (vzestupne, sestupne) overime
               velikosti obsahu bunek (ma-li se prehazovat, nebo ne) */
            if (res == smer) {
                /* prehozeni poradi radku */
                zmena = 1;
                /* radek lezici za radkem A oznacime B */
                B = A -> Next;
                /* tady se to deje ponekud zmatenym (ale spravnym)
                   zpusobem ... jednoduse receno poprehazuji se
                   ukazatele na predchozi/pristi prvek u obou radku
                   a taktez u jejich sousedu (tj. predchudce radku A,
                   existuje-li, a radku leziciho za radkem B, je-li) */
                if (A -> Previous != NULL) A -> Previous -> Next = B;
                else UkDtb -> Polozky = B;
                B -> Previous = A -> Previous;
                A -> Previous = B;
                A -> Next = B -> Next;
                if (B -> Next != NULL) B -> Next -> Previous = A;
                B -> Next = A;
            }
            /* V pripade, ze jsme nic neprehazovali, posuneme
               ukazatel na radek A o jedno misto doprava.
               (pokud k zamene doslo, pak "posunuti" bylo provedeno
               automaticky tim, ze ukazatel na radek A se nezmenil,
               ale "posunul" se cely radek A) */
            else A = A -> Next;
        }
        /* zmensime velikost pole, ve kterem porovnavame radky,
           nebot posledni radek jiz urcite obsahuje pozadovane
           data */
        max--;
    }
    return;
}
/*                                                                */
/* -------------------------------------------------------------- */



int find_command(char *txt) {
    int _res = -1, i = 0, r;
    char *TXT[128];
    strcpy((char*)TXT, txt);
    uppercase((char*)TXT);
    while ((i < CMD_COUNT) && (_res == -1)) {
        if ((r = strcmp((char*)commands[i], (char*)TXT)) == 0) _res = i;
        i++;
    }
    return _res;
}

int find_parameter(char *txt) {
    int _res = -1, i = 0, r;
    char *TXT[128];
    strcpy((char*)TXT, txt);
    uppercase((char*)TXT);
    while ((i < CMD_COUNT) && (_res == -1)) {
        if ((r = strcmp((char*)parameters[i], (char*)TXT)) == 0) _res = i;
        i++;
    }
    return _res;
}


void add_column(tCmmnd command, tUkDtb UkDtb) {
    int i = 2, typ = 0, velikost = 8;
    char *nazev[32];
    while (i < command.cnt-1) {
        switch (find_parameter(command.param[i++])) {
            case 4 :    /* NAME */
                strcpy((char*)nazev, command.param[i++]);
                break;
            case 5 :    /* TYPE */
                typ = atoi(command.param[i++]);
                break;
            case 6 :    /* SIZE */
                velikost = atoi(command.param[i++]);
                break;
            default:;
        }
    }
    vytvor_sloupec(UkDtb, (char*)nazev, typ, velikost);    
    return;
}

void delete_row(tCmmnd command, tUkDtb UkDtb) {
    tUkPolozka Polozka;
    int i = 4, shoda;
    Polozka = UkDtb -> Polozky;
    while ((Polozka = hledej_radek(UkDtb, Polozka, hledej_sloupec(UkDtb, command.param[2]), command.param[3])) != NULL) {
        shoda = 0;
        while ((i < command.cnt-1) && (shoda == 0)) {
            shoda = porovnej((char*)Polozka -> UkSloupec[hledej_sloupec(UkDtb, command.param[i++])], (char*)command.param[i++]);
        }
        if (shoda == 0) {
            smaz_radek(UkDtb, Polozka);
            Polozka = UkDtb -> Polozky;
        } else Polozka = Polozka -> Next;
        i = 4;
    }
    return;
}


void command_process(tCmmnd *command, tUkDtb *UkDtb, int *_res) {
    int i, c_n, _r;
    tUkPolozka Polozka;
    c_n = find_command((char*)command -> param[0]);
    switch (c_n) {
        case 0 :    /* EXIT */
            exit(0);
            break;
        case 1 :    /* CLOSE */
            *UkDtb = smaz_dtb(*UkDtb);
            break;
        case 2 :    /* OPEN filename */
            *UkDtb = nacti_dtb(command -> param[1]);
            if (*UkDtb == NULL) /* unable to open file */ *_res = -4;
            break;
        case 3 :    /* IMPORT FORMAT filename [TRUE/FALSE]*/
            switch (find_parameter(command -> param[1])) {
                case 0 :    /* CSV */
                    switch (find_parameter(command -> param[3])) {
                        case 8: /* [HEADER?] TRUE */
                            *UkDtb = import_CSV(command -> param[2], 1);
                            break;
                        default:
                            *UkDtb = import_CSV(command -> param[2], 0);
                    }
                    break;
                default:;
            }
            if (*UkDtb == NULL) /* unable to open file */ *_res = -4;
            break;
        case 4 :    /* CREATE */
            *UkDtb = nova_dtb();
            if (*UkDtb == NULL) /* unable to create new database */ *_res = -5;
            break;
        case 5 :    /* SAVE filename */
            _r = uloz_dtb(*UkDtb, (char*)command -> param[1]);
            if (_r == -1) /* unable to save file */ *_res = -3;
            break;
        case 6 :    /* EXPORT FORMAT filename [HTML page title]*/
            switch (find_parameter(command -> param[1])) {
                case 0 :    /* CSV */
                    switch (find_parameter(command -> param[3])) {
                        case 8: /* TRUE */
                            _r = export_CSV(*UkDtb, command -> param[2], 1);
                            break;
                        default:
                            _r = export_CSV(*UkDtb, command -> param[2], 0);
                    }
                    break;
                case 1 :    /* HTML */
                    _r = export_HTML(*UkDtb, command -> param[2], command -> param[3]);
                    break;
                default: /* unknown file format */
                    _r = -1;
            }
            if (_r == -1) /* unable to save file */ *_res = -3;
            break;
        case 7 :    /* ADD (ROW item=text [...]/COLUMN NAME=text TYPE=type SIZE=size) */
            switch (find_parameter(command -> param[1])) {
                case 2 :    /* COLUMN */
                    add_column(*command, *UkDtb);
                    break;
                case 3 :    /* ROW */
                    Polozka = vytvor_radek(*UkDtb);
                    i = 2;
                    while (i < command -> cnt-1) zapis_polozku(*UkDtb, Polozka, hledej_sloupec(*UkDtb, command -> param[i++]), command -> param[i++]);
                    break;
                default: /* unknown parameter */
                    *_res = -2;
            }
            break;
        case 8 :    /* DELETE (ROW item=text[...]/COLUMN NAME=text) */
            switch (find_parameter(command -> param[1])) {
                case 2 :    /* COLUMN */
                    switch (find_parameter(command -> param[2])) {
                        case 4 :    /* NAME */
                            smaz_sloupec(*UkDtb, hledej_sloupec(*UkDtb, command -> param[3]));
                            break;
                        default: /* unknown parameter */
                            *_res = -2;
                    }
                    break;
                case 3 :    /* ROW */
                    delete_row(*command, *UkDtb);
                    break;
                default: /* unknown parameter */
                    *_res = -2;
            }
            break;
        case 9 :    /* ECHO [...] */
            for (i = 1; i < command -> cnt; printf("%s ", command -> param[i++]));
            printf("\n");
            break;
        case 10 :    /* PAUSE */
            printf("< Please press ENTER >");
            fflush(stdin);
            getchar();
            break;
        default: /* unknown command */
            *_res = -1;
    }
    command -> cnt = 0;
    command -> param[0][0] = '\0';
    return;
}


/* -------------------------------------------------------------- */
/* vykonava prikazy zadane v souboru filename.                    */

int analyze_script(tUkDtb *UkDtb, char *filename) {
    char *buffer[1024], *start;
    FILE *soubor;
    tFlags flags;
    tCmmnd command;
    int _ret;
    
    flags.comment = 0;
    flags.comment_begin = 0;
    flags.comment_end = 0;
    flags.string = 0;
    flags.string_begin = 0;
    command.cnt = 0;
    command.param[0][0] = '\0';

     /*pokusi se otevrit soubor se skriptem pro cteni */
     if ((soubor = fopen(filename, "r")) == NULL) return -3; /* unable to open script file */
     while (fgets((char*)buffer, 1023, soubor) != NULL) {
         start = (char*)buffer;
         while(strlen(start) > 0) char_process(*start++, UkDtb, &flags, &command, 1, "= \n", ";", &command_process, &_ret);
     }     
     
     return _ret;
}
/*                                                                */
/* -------------------------------------------------------------- */


