/*
    module: cvrin.c
    purpose: cube and cover input routines
*/
/** MM: obsahuje verzie pre retazec */

#include "espresso.h"

static bool3 line_length_error;
static int lineno;

static int read_symbolic_string(const char **stringPtr, pPLA PLA, char *word, symbolic_t **retval);

/** MM: pomocna funkcia pre posun v retazci o jeden token oddeleny medzerou, entrom alebo talbulatorom */
static int getNextToken(const char **stringPtr){
    char tmp = **stringPtr;
    const char *ptr = *stringPtr;
    //cout << "char = " << tmp << endl;
    
    /* preskocenie uvodnych medzier; nemusia byt pritomne */
    while (tmp==' ' || tmp=='\t' || tmp=='\n') { // posuvanie dokym je biele miesto
        tmp = *++ptr; 
        //cout << "char = " << tmp << endl;
    }
    /* preskocenie neprazdnych znakov = preskocenie posledne spracovaneho tokenu */
    while (tmp!='\0' && tmp!=' ' &&  tmp!='\t' && tmp!='\n') {
        tmp = *++ptr; 
        //cout << "char = " << tmp << endl;
    }
    if (tmp == '\0') { //ak sa narazilo na roniec retazca, jedna sa akoby o EOF
        //cout << "char = " << tmp << endl;
        *stringPtr = ptr;
        return -1; //ak -1, posledne citany token bol posledny
    }
    /* preskocenie medzier */
    while (tmp==' ' || tmp=='\t' || tmp=='\n') { // posuvanie dokym je biele miesto
        tmp = *++ptr; 
        //cout << "char = " << tmp << endl;
    }
    *stringPtr = ptr;
    //cout << "char = " << tmp << endl;
    return 0; //ak nula, ukazatel ukazuje na zaciatok tokenu
}

/** MM: osetrene pre NULL vystup */
/** MM: verzia pre string */
/** ptr posunie */
static void skip_line_string(const char **stringPtr, register FILE *fpout, register int echo)
{
    register int ch;
    const char *ptr;
    ptr = *stringPtr;
    ch = *ptr;
    while ( ch != '\0' && ch != '\n'){
    	if (echo && (fpout!=NULL) ) putc(ch, fpout);
    	ch = *(++ptr);
    }
    if (echo && (fpout!=NULL))
    	putc('\n', fpout);
    lineno++;
    *stringPtr = ptr;
}

/** MM: verzia pre string */
/** ptr posunie */
static char *get_word_string(const char **stringPtr, register char *word)
{
    register int ch, i = 0;
    const char *ptr = *stringPtr;
    ch = *ptr;
    while ( ch != '\0' && isspace(ch)) ch = *(++ptr);

    word[i++] = ch;
    ch = *(++ptr);
    while ( ch != '\0' && !isspace(ch) ){
    	word[i++] = ch;
    	ch = *(++ptr);
    }
    word[i++] = '\0';
    
    *stringPtr = ptr;
    return word;
}

/*
 *  Yes, I know this routine is a mess
 */
/** MM: Nacita 1 riadok zo vstupu */
/** MM: upravuje PLA->label,... */
/** MM: sama o sebe nic nealokuje, ale fukcie, ktore vola ano */
/** MM: vracia -1 len v pripadoch, ked povodne volala fatal alebo exit */
/** MM: verzia pre string */
static int read_cube_string(const char **stringPtr, pPLA PLA)
{
    register int var, i;
    pcube cf = cube->temp[0], cr = cube->temp[1], cd = cube->temp[2];
    bool3 savef = FALSE3, saved = FALSE3, saver = FALSE3;
    char token[256]; 			/* for kiss read hack */
    char tmp;
    int varx, first, last, offset;	/* for kiss read hack */
    const char *ptr = *stringPtr;

    set_clear(cf, cube->size);

    /* Loop and read binary variables */
    for(var = 0; var < cube->num_binary_vars; var++){
        tmp = *ptr++;
    	switch(tmp) {
    	    case '\0':
                goto bad_char;
    	    case '\n':
        		if (! line_length_error)
        		    if (erroroutput) fprintf(erroroutput, "product term(s) %s\n", "span more than one line (warning only)\n");
        		line_length_error = TRUE3;
        		lineno++;
        		var--;
        		break;
    	    case ' ': case '|': case '\t':
                var--;
                break;
    	    case '2': case '-':
        		set_insert(cf, var*2+1);
    	    case '0':
        		set_insert(cf, var*2);
        		break;
    	    case '1':
        		set_insert(cf, var*2+1);
        		break;
    	    case '?':
        		break;
    	    default:
        		if (!isspace(tmp)) goto bad_char;
        		var--;
        		break;
    	}
    }


    /* Loop for the all but one of the multiple-valued variables */	
    for(var = cube->num_binary_vars; var < cube->num_vars-1; var++)

    	/* Read a symbolic multiple-valued variable */
    	if (cube->part_size[var] < 0) {
    	    if (sscanf(ptr, "%s", token) == 1) getNextToken(&ptr);
    	    else { *stringPtr = ptr; return -1; }
    	    if (str_equal(token, "-") || str_equal(token, "ANY")) {
        		if (kiss && var == cube->num_vars - 2) {
        		    /* leave it empty */
        		} else {
        		    /* make it full */
        		    set_or(cf, cf, cube->var_mask[var]);
        		}
    	    } else if (str_equal(token, "~")) {
        		;
        		/* leave it empty ... (?) */
    	    } else {
        		if (kiss && var == cube->num_vars - 2)
        		    varx = var - 1, offset = ABS(cube->part_size[var-1]);
        		else
        		    varx = var, offset = 0;
        		/* Find the symbolic label in the label table */
        		first = cube->first_part[varx];
        		last = cube->last_part[varx];
        		/** MM: prechadzanie pola labelov a hladanie volneho miesta na vlozenie aktualneho, ak sa v poli este nenachadza */
        		for(i = first; i <= last; i++)
        		    if (PLA->label[i] == (char *) NULL) {
            			PLA->label[i] = util_strsav(token);	/* add new label */
            			set_insert(cf, i+offset);
            			break;
        		    } else if (str_equal(PLA->label[i], token)) {
            			set_insert(cf, i+offset);	/* use column i */
            			break;
        		    }
        		if (i > last) { /** MM: namiesto volania fatal-u */
            		snprintf(errorbuffer, sizeof(errorbuffer), "declared size of variable %d (counting from variable 0) is too small", var); /** MM: pridane kvoli hlaske pre vynimku */
        		    if (erroroutput) { 
                        fprintf(erroroutput, "espresso: declared size of variable %d (counting from variable 0) is too small\n", var);
                        *stringPtr = ptr;
             		    return -1; /** MM: toto je zavazna chyba a musi byt ukoncene nacitavanie */
                    }
        		}
    	    }
    	
    	} else for(i = cube->first_part[var]; i <= cube->last_part[var]; i++){
            tmp = *ptr++;
    	    switch (tmp) {
        		case '\0':
        		    goto bad_char;
        		case '\n':
        		    if (! line_length_error)
            			if (erroroutput) fprintf(erroroutput, "espresso: product term(s) span more than one line (warning only)\n");
        		    line_length_error = TRUE3;
        		    lineno++;
        		    i--;
        		    break;
        		case ' ': case '|': case '\t':
        		    i--;
        		    break;
        		case '1':
        		    set_insert(cf, i);
        		case '0':
        		    break;
        		default:
        		    if (!isspace(tmp)) goto bad_char;
        		    i--;
        		    break;
    	    }
        }

    /* Loop for last multiple-valued variable */
    if (kiss) {
    	saver = savef = TRUE3;
    	(void) set_xor(cr, cf, cube->var_mask[cube->num_vars - 2]);
    } else
	set_copy(cr, cf);
    set_copy(cd, cf);
    for(i = cube->first_part[var]; i <= cube->last_part[var]; i++){
        tmp = *ptr++;
    	switch (tmp) {
    	    case '\0':
        		goto bad_char;
    	    case '\n':
        		if (! line_length_error)
        		    if (erroroutput) fprintf(erroroutput, "product term(s) %s\n",	"span more than one line (warning only)\n");
        		line_length_error = TRUE3;
        		lineno++;
        		i--;
        		break;
    	    case ' ': case '|': case '\t':
        		i--;
        		break;
    	    case '4': case '1':
        		if (PLA->pla_type & F_type)
        		    set_insert(cf, i), savef = TRUE3;
        		break;
    	    case '3': case '0':
        		if (PLA->pla_type & R_type)
        		    set_insert(cr, i), saver = TRUE3;
        		break;
    	    case '2': case '-':
        		if (PLA->pla_type & D_type)
        		    set_insert(cd, i), saved = TRUE3;
    	    case '~':
        		break;
    	    default:
        		if (!isspace(tmp)) goto bad_char;
        		i--;
        		break;
    	}
    }
    
    *stringPtr = ptr; 
    if (savef) { PLA->F = sf_addset(PLA->F, cf); if (PLA->F == NULL) return -1; /** MM: ak chyba alokacie */}
    if (saved) { PLA->D = sf_addset(PLA->D, cd); if (PLA->D == NULL) return -1; /** MM: ak chyba alokacie */}
    if (saver) { PLA->R = sf_addset(PLA->R, cr); if (PLA->R == NULL) return -1; /** MM: ak chyba alokacie */}
    return 0;

bad_char:
    if (erroroutput) fprintf(erroroutput, "(warning): input line #%d ignored\n", lineno);
    skip_line_string(&ptr, standardoutput, TRUE3);
    *stringPtr = ptr;
    return 0; /** MM: 0, lebo chybny riadok neznamena zavaznu chybu nacitania */
}

/** MM: Hlavna nacitacia funkcia - parsuje vstupny "subor", ziska inicializacne data a opakovane vola read_cube() */
/** MM: upravuje fp, PLA->F, PLA->D, PLA->R, PLA->label, PLA->symbolic, PLA->phase, PLA->symbolic_output, PLA->pla_type... */
/** MM: dokym sa neprejde k read_cube, upravuju sa len primitivne premenne struktury cube */
/** MM: pri chybe vrati -1, cube, cdata a  PLA budu v stave, ze setdown_cube a free_PLA nesposobia pad */
/** MM: chyba nacitania je aj ked nedojde k nacitaniu ziadneho riadku => PLA->F == NULL, ale to zisti az volajuci */
/** MM: verzia pre string */
static int parse_pla_string(const char **stringPtr, pPLA PLA)
{
    int i, var, ch, np, last;
    int tmp; /** MM: kvoli navratovej hodnote */
    char word[256];
    const char *ptr = *stringPtr;

    lineno = 1;
    line_length_error = FALSE3;
    /** MM: nastavenie hodnot kocky tak, aby sa nahodne spusteny cube_setup predcasne ukoncil */
    cube->num_binary_vars = -1;
    cube->num_vars = -2;

loop:
    switch(*ptr++) {
    	case '\0':
            *stringPtr = --ptr; /** --ptr, aby to pri opatovnom spustneni nespadlo/nezacyklilo sa */
    	    return 0; /** MM: doslo sa na koniec bez .end */
    
    	case '\n':
    	    lineno++;
    
    	case ' ': case '\t': case '\f': case '\r':
    	    break;
    
    	case '#':
    	    --ptr;
    	    skip_line_string(&ptr, eatoutput, echo_comments);
    	    break;
    
    	case '.':
    	    /* .i gives the cube input size (binary-functions only) */
    	    if (str_equal(get_word_string(&ptr, word), "i")) {
        		if (cube->fullset != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .i ignored\n");
        		    skip_line_string(&ptr, standardoutput, /* echo */ FALSE3);
        		} else {
        		    if (sscanf(ptr, "%d", &cube->num_binary_vars) != 1){
                        fatal2("error reading .i");
                        *stringPtr = ptr;
                        return -1;
                    }
                    getNextToken(&ptr); /** MM: nutne, aby sa po nacitani posunul aj ukazatel */
        		    cube->num_vars = cube->num_binary_vars + 1; /** MM: nastavenie num_vars, aby boli hodnoty oboch premennych spravne */
        		    cube->part_size = ALLOC(int, cube->num_vars);
        		    if (cube->part_size == NULL) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		}
    
    	    /* .o gives the cube output size (binary-functions only) */
    	    } else if (str_equal(word, "o")) {
        		if (cube->fullset != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .o ignored\n");
        		    skip_line_string(&ptr, standardoutput, /* echo */ FALSE3);
        		} else {
        		    if (cube->part_size == NULL){
                        fatal2(".o cannot appear before .i");
                        *stringPtr = ptr;
                        return -1; /** MM: ak chyba */
                        
                    }
        		    if (sscanf(ptr, "%d", &(cube->part_size[cube->num_vars-1]))!=1){
                    	fatal2("error reading .o");
                    	*stringPtr = ptr;
                    	return -1; /** MM: ak chyba */
                    }
                    getNextToken(&ptr);
        		    tmp = cube_setup(); 
        		    if (tmp == -1){ /** MM: ak chyba alokacie */
            		    *stringPtr = ptr;
                        return -1;
                    }
        		    tmp = PLA_labels(PLA); 
        		    if (tmp == -1){ /** MM: ak chyba alokacie */
                        *stringPtr = ptr;
                        return -1;
                    }
        		}
    
    	    /* .mv gives the cube size for a multiple-valued function */
    	    } else if (str_equal(word, "mv")) {
        		if (cube->fullset != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .mv ignored\n");
        		    skip_line_string(&ptr, standardoutput, /* echo */ FALSE3);
        		} else {
        		    if (cube->part_size != NULL){
            			fatal2("cannot mix .i and .mv"); /** MM: ak chyba citania*/
            			*stringPtr = ptr;
                        return -1;
                    }
        		    if (sscanf(ptr,"%d %d", &cube->num_vars,&cube->num_binary_vars) != 2){
                        fatal2("error reading .mv"); /** MM: ak chyba citania*/
                        *stringPtr = ptr;
                        return -1;
                    }
                    getNextToken(&ptr);
                    getNextToken(&ptr);
        		    if (cube->num_binary_vars < 0){
                        fatal2("num_binary_vars (second field of .mv) cannot be negative"); /** MM: ak chyba */
                        *stringPtr = ptr;
                        return -1;
                    }
        		    if (cube->num_vars < cube->num_binary_vars){
                    	fatal2("num_vars (1st field of .mv) must exceed num_binary_vars (2nd field of .mv)"); /** MM: ak chyba */
                    	*stringPtr = ptr;
                        return -1;
                    }
        		    cube->part_size = ALLOC(int, cube->num_vars);
        		    if (cube->part_size == NULL) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie*/
        		    for(var=cube->num_binary_vars; var < cube->num_vars; var++)
            			if (sscanf(ptr, "%d", &(cube->part_size[var])) != 1){
            			    fatal2("error reading .mv"); /** MM: ak chyba citania*/
            			    *stringPtr = ptr;
                            return -1; /** MM: okrem setdown_cube zavolat aj FREE(cube->part_size)!!! */
                        }
                        getNextToken(&ptr);
        		    tmp = cube_setup();
        		    if (tmp == -1) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie / premennych */
        		    tmp = PLA_labels(PLA);
        		    if (tmp == -1) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		}
    
    	    /* .p gives the number of product terms -- we ignore it */
    	    } else if (str_equal(word, "p")){
        		sscanf(ptr, "%d", &np); /** MM: tato hodnota sa ignoruje, preto nas nezaujima, ako skonci jej citanie */
        		getNextToken(&ptr);
            }
    	    /* .e and .end specify the end of the file */
    	    else if (str_equal(word, "e") || str_equal(word,"end")){
                *stringPtr = ptr;
        		return 0; /** MM: doslo sa na korektny koniec */
            }
    	    /* .kiss turns on the kiss-hack option */
    	    else if (str_equal(word, "kiss"))
        		kiss = TRUE3;
    
    	    /* .type specifies a logical type for the PLA */
    	    else if (str_equal(word, "type")) {
        		(void) get_word_string(&ptr, word);
        		for(i = 0; pla_types[i].key != 0; i++)
        		    if (str_equal(pla_types[i].key + 1, word)) {
            			PLA->pla_type = pla_types[i].value;
            			break;
        		    }
        		if (pla_types[i].key == 0){
        		    fatal2("unknown type in .type command"); /** MM: ak chyba zadaneho typu PLA */
        		    *stringPtr = ptr;
        		    return -1;
                }
    
    	    /* parse the labels */
    	    } else if (str_equal(word, "ilb")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .ilb or .ob"); /** MM: ak chyba */
        		    *stringPtr = ptr;
        		    return -1; 
                }
        		if (PLA->label == NULL)
        		    PLA_labels(PLA);
        		for(var = 0; var < cube->num_binary_vars; var++) {
        		    (void) get_word_string(&ptr, word);
        		    i = cube->first_part[var];
        		    PLA->label[i+1] = util_strsav(word);
        		    PLA->label[i] = ALLOC(char, strlen(word) + 6);
        		    if ( (PLA->label[i+1] == NULL) || (PLA->label[i] == NULL) ) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		    (void) snprintf(PLA->label[i], strlen(word) + 6, "%s.bar", word); /** MM: zmenene na secure version */
        		}
    	    } else if (str_equal(word, "ob")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .ilb or .ob"); /** MM: ak chyba */
        		    *stringPtr = ptr;
                    return -1;
                }
        		if (PLA->label == NULL)
        		    tmp = PLA_labels(PLA); 
                    if (tmp == -1) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		var = cube->num_vars - 1;
        		for(i = cube->first_part[var]; i <= cube->last_part[var]; i++) {
        		    (void) get_word_string(&ptr, word);
        		    PLA->label[i] = util_strsav(word);
        		    if (PLA->label[i] == NULL) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		}
    	    /* .label assigns labels to multiple-valued variables */
    	    } else if (str_equal(word, "label")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .label"); /** MM: ak chyba */
        		    *stringPtr = ptr;
                    return -1;
                }
        		if (PLA->label == NULL)
        		    tmp = PLA_labels(PLA);
        		    if (tmp == -1) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		if (sscanf(ptr, "var=%d", &var) != 1){
        		    fatal2("Error reading labels"); /** MM: ak chyba citania */
        		    *stringPtr = ptr;
                    return -1;
                }
                /** MM: trochu zlozitejsie posunutie */
                if (isspace(*(ptr+4))) getNextToken(&ptr); /** MM: ak je medzi "var=" a cislom medzera, spravi sa o jeden posun viac */
                getNextToken(&ptr); /** MM: jeden posun sa spravi vzdy */
        		for(i = cube->first_part[var]; i <= cube->last_part[var]; i++) {
        		    (void) get_word_string(&ptr, word);
        		    PLA->label[i] = util_strsav(word);
        		    if (PLA->label[i] == NULL ) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		}
    
    	    } else if (str_equal(word, "symbolic")) {
        		symbolic_t *newlist, *p1;
        		if (read_symbolic_string(&ptr, PLA, word, &newlist)) {
        		    if (PLA->symbolic == NIL(symbolic_t)) {
            			PLA->symbolic = newlist;
        		    } else {
                        /** MM: prechadzanie spojovym zoznamom do konca a pridanie noveho listu */
            			for(p1=PLA->symbolic;p1->next!=NIL(symbolic_t); p1=p1->next){
            			}
            			p1->next = newlist;
        		    }
        		} else {
        		    fatal2("error reading .symbolic"); /** MM: ak chyba */
        		    *stringPtr = ptr;
                    return -1;
        		}
    
    	    } else if (str_equal(word, "symbolic-output")) {
        		symbolic_t *newlist, *p1;
        		if (read_symbolic_string(&ptr, PLA, word, &newlist)) {
        		    if (PLA->symbolic_output == NIL(symbolic_t)) {
            			PLA->symbolic_output = newlist;
        		    } else {
            			for(p1=PLA->symbolic_output;p1->next!=NIL(symbolic_t); p1=p1->next){
            			}
                        p1->next = newlist;
        		    }
        		} else {
        		    fatal2("error reading .symbolic-output"); /** MM: ak chyba */
        		    *stringPtr = ptr;
                    return -1;
        		}
        		
    	    /* .phase allows a choice of output phases */
    	    } else if (str_equal(word, "phase")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .phase"); /** MM: ak chyba */
        		    *stringPtr = ptr;
                    return -1;
                }
        		if (PLA->phase != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .phase ignored\n");
        		    skip_line_string(&ptr, standardoutput, /* echo */ FALSE3);
        		} else {
        		    do ch = *ptr++; while (ch == ' ' || ch == '\t');
        		    --ptr;
        		    PLA->phase = set_save(cube->fullset);
        		    if (PLA->phase==NULL) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		    last = cube->last_part[cube->num_vars - 1];
        		    for(i=cube->first_part[cube->num_vars - 1]; i <= last; i++)
            			if ((ch = *ptr++) == '0')
            			    set_remove(PLA->phase, i);
            			else if (ch != '1'){
            			    fatal2("only 0 or 1 allowed in phase description"); /** MM: ak chyba parametra */
            			    *stringPtr = ptr;
                            return -1;
                        }
        		}
    
    	    /* .pair allows for bit-pairing input variables */
    	    } else if (str_equal(word, "pair")) {
        		int j;
        		if (PLA->pair != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .pair ignored\n");
        		} else {
        		    ppair pair;
        		    PLA->pair = pair = ALLOC(pair_t, 1);
        		    if (PLA->pair == NULL) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		    if (sscanf(ptr, "%d", &(pair->cnt)) != 1){
                    	fatal2("syntax error in .pair"); /** MM: ak chyba vstupu */
                    	*stringPtr = ptr;
                        return -1;
                    }
                    getNextToken(&ptr);
        		    pair->var1 = ALLOC(int, pair->cnt);
        		    pair->var2 = ALLOC(int, pair->cnt);
        		    if ( (pair->var1 == NULL) || (pair->var2 == NULL) ) { *stringPtr = ptr; return -1; } /** MM: ak chyba alokacie */
        		    for(i = 0; i < pair->cnt; i++) {
            			(void) get_word_string(&ptr, word);
            			if (word[0] == '(') (void) strcpy(word, word+1);
            			if (label_index(PLA, word, &var, &j)) {
            			    pair->var1[i] = var+1;
            			} else {
            			    fatal2("syntax error in .pair"); /** MM: ak chyba */
            			    *stringPtr = ptr;
                            return -1;
            			}
            
            			(void) get_word_string(&ptr, word);
            			if (word[strlen(word)-1] == ')') {
            			    word[strlen(word)-1]='\0';
            			}
            			if (label_index(PLA, word, &var, &j)) {
            			    pair->var2[i] = var+1;
            			} else {
            			    fatal2("syntax error in .pair"); /** MM: ak chyba */
            			    *stringPtr = ptr;
                            return -1;
            			}
        		    }
        		}
        		
    	    } else {
        		if (echo_unknown_commands)
        		    fprintf(eatdotsoutput, "%c%s ", ch, word);
        		skip_line_string(&ptr, eatdotsoutput, echo_unknown_commands);
    	    }
    	    break;
    	/** MM: spusti sa, ak nie su ziadne ".nieco" prikazy */
    	default:
    	    --ptr;
    	    if (cube->fullset == NULL) { /** MM: fullset sa inicializuje prostrednictvom cube_setup */
        		if (echo_comments)
        		    fputc('#', eatoutput);
        		skip_line_string(&ptr, eatoutput, echo_comments);
        		break;
    	    }
    	    /** MM: ak prebieha prve citanie, inicializuju sa struktury */
    	    if (PLA->F == NULL) {
        		PLA->F = new_cover(10);
        		PLA->D = new_cover(10);
        		PLA->R = new_cover(10);
        		if ( (PLA->F == 0) || (PLA->D == 0) || (PLA->R == 0) ){ /** MM: ak chyba alokacie */
                    *stringPtr = ptr;
                    return -1; /** MM: o korektnu dealokaciu sa postara free_PLA */
                }
    	    }
    	    /** MM: nacita sa jedna kocka */
    	    if (read_cube_string(&ptr, PLA) == -1){ /** MM: neskoncilo citanie zavaznou chybou? ["az" v jednom pripade; ostatne su warningy]*/
                /** MM: netreba nic dealokovat */
                *stringPtr = ptr;
                return -1;
            }
    }
    goto loop;
}
/*
    read_pla -- read a PLA from a file

    Input stops when ".e" is encountered in the input file, or upon reaching
    end of file.

    Returns the PLA in the variable PLA after massaging the "symbolic"
    representation into a positional cube notation of the ON-set, OFF-set,
    and the DC-set.

    needs_dcset and needs_offset control the computation of the OFF-set
    and DC-set (i.e., if either needs to be computed, then it will be
    computed via complement only if the corresponding option is TRUE3.)
    pla_type specifies the interpretation to be used when reading the
    PLA.

    The phase of the output functions is adjusted according to the
    global option "pos" or according to an imbedded .phase option in
    the input file.  Note that either phase option implies that the
    OFF-set be computed regardless of whether the caller needs it
    explicitly or not.

    Bit pairing of the binary variables is performed according to an
    imbedded .pair option in the input file.

    The global cube structure also reflects the sizes of the PLA which
    was just read.  If these fields have already been set, then any
    subsequent PLA must conform to these sizes.

    The global flags trace and summary control the output produced
    during the read.

    Returns a status code as a result:
	EOF (-1) : End of file reached before any data was read
	> 0	 : Operation successful
*/

/** nacita PLA, spracuje KISS, pair, symbolic,... [vsetko co povodna okrem complementov a pos] */
/** MM: ak chyba, vrati -1; inak 0 */
/** MM: upratuje volajuci */
/** MM: meni ale aj zalohuje a obnovuje KISS */
/** MM: needs_dcset a needs_offset su uz sucastou computeSets */
/** MM: pla_type = input_type, defaultne a nemenne je to FD_type */
int read_pla_string(const char **stringPtr, pPLA PLA)
{
    //pPLA tmpPLA;
    int i, second, third, tmp; /** MM: tmp pre kontrolu navratovych hodnot */
    long time;
    cost_t cost; /** MM: struktura popisujuca cenu pokrytia - kvoli debugu*/

    if ( (stringPtr==NULL) || (PLA==NULL) ) return -1;
    
    bool3 oldkiss = kiss; /** MM: kiss moze byt stanoveny nastaveniami, pripadne zmeneny pocas nacitavania */

    time = ptime();
    
    /** MM: nacitanie PLA zo suboru */
    tmp = parse_pla_string(stringPtr, PLA); 
    /** MM: F == NULL IFF sa nenacital ani jeden riadok -> cube_struct je v podstate prazdna*/
    if ( (tmp == -1) || (PLA->F == NULL) ){ /** MM: kontrola oboch chyb */
        kiss = oldkiss;
        fatal2("PLA couldn't be loaded");
        return -1;
    }

    /* This hack merges the next-state field with the outputs */
    /** MM: len upravuje hodnoty v cube->num_vars na kladne */
    for(i = 0; i < cube->num_vars; i++) {
    	cube->part_size[i] = ABS(cube->part_size[i]);
    }
    /** MM: podla dokumentacie je kiss "Sets up a kiss-style minimization problem. This is a hack." [commandline option]*/
    if (kiss) {
        third = cube->num_vars - 3;
        second = cube->num_vars - 2;
        if (cube->part_size[third] != cube->part_size[second]) {
            fatal2(" with .kiss option, third to last and second\nto last variables must be the same size.\n");
            kiss = oldkiss;
            return -1;
        }
        /** MM: ak je chybne zadany parameter -ekiss; vychodzie boli hodnoty ukazatelov v "kiss.pla" */
		if(PLA->label[cube->first_part[second]] != NULL || PLA->label[cube->first_part[third]] == NULL){
			fatal2("this is not a kiss styled PLA");
			kiss = oldkiss;
			return -1;
		}
    	for(i = 0; i < cube->part_size[second]; i++) {
            PLA->label[i + cube->first_part[second]] =
            util_strsav(PLA->label[i + cube->first_part[third]]);
        }
        /** MM: nejaka magia so zmenou velkosti alokovanej pamati pre kocku */
        cube->part_size[second] += cube->part_size[cube->num_vars-1];
        /** MM: zrusia sa nejake data; part_size sa nezmeni */
        setdown_cube();
        cube->num_vars--; /** MM: oprava memory leaku: najskor setdown a az potom uprava num_vars!!! */
        /** MM: kocka sa opat dostane do konzistentneho stavu */
        tmp = cube_setup();
        if (tmp == -1) { /** MM: chyba inicializacie kocky */
            kiss = oldkiss;
			return -1;
        }
    }
    kiss = oldkiss; /* MM: obvova povodneho kiss, aby sa mohol nacitat dalsi obvod podla povodnych nastaveni */

    /** MM: ak sa traceuje, vypise statistiku */
    if (trace) {
	   totals(time, READ_TIME, PLA->F, &cost);
    }

    /** MM: povodne tu bola cast dopocitavajuca SETy */

//	/** MM: povodne tomu predchadzala vetva s "pos" */
//	/* Check for phase rearrangement of the functions */
//    if (PLA->phase != NULL) { 
//		/** MM: set_phase modifikuje ON a OFF set; treba dopocitat OFF-set!!! */
//		if (PLA->pla_type==F_type || PLA->pla_type==FD_type) {
//			free_cover(PLA->R);
//			PLA->R = complement(cube2list(PLA->F, PLA->D));
//			if (PLA->R == NULL){ /** MM: ak chyba alokacie */
//				return -1; /** MM: ak chyba alokacie v complement */
//			}
//			/* treba upravit typ, aby sa to vypocitavalo len raz */
//			PLA->pla_type |= R_type;
//		} 
//        tmpPLA = set_phase(PLA);
//        if (tmpPLA==NULL) return -1; /** MM: ak chyba alokacie v set_phase */
//        
//    }

    /* Setup minimization for two-bit decoders */
//    if (PLA->pair != (ppair) NULL) {
//        tmp = set_pair(PLA);
//        if (tmp == -1) return -1; /** MM: ak chyba v set_pair */
//    }
//
//    if (PLA->symbolic != NIL(symbolic_t)) {
//        EXEC(tmp = map_symbolic(PLA), "MAP-INPUT  ", PLA->F);
//        if (tmp != 0) return -1; /** MM: ak chyba v map_symbolic*/ 
//    }
//    if (PLA->symbolic_output != NIL(symbolic_t)) {
//        EXEC(tmp = map_output_symbolic(PLA), "MAP-OUTPUT ", PLA->F);
//        if (tmp != 0) return -1; /** MM: ak chyba v map_output_symbolic */
//        /** MM: prepocitanie noveho off-setu? */
//        PLA->pla_type &= ~R_type; /** MM: toto zabezpeci prepocitanie OFF-setu, ak ho bude potreba */
//    }
    
    return 0;
}

int read_pla(FILE* fp, pPLA PLA)
{
    //pPLA tmpPLA;
    int i, second, third, tmp; /** MM: tmp pre kontrolu navratovych hodnot */
    long time;
    cost_t cost; /** MM: struktura popisujuca cenu pokrytia - kvoli debugu*/
    
    if ( (fp==NULL) || (PLA==NULL) ) return -1;
    
    bool3 oldkiss = kiss; /** MM: kiss moze byt stanoveny nastaveniami, pripadne zmeneny pocas nacitavania */

    time = ptime();
    
    /** MM: nacitanie PLA zo suboru */
    tmp = parse_pla(fp, PLA); 
    /** MM: F == NULL IFF sa nenacital ani jeden riadok -> cube_struct je v podstate prazdna*/
    if ( (tmp == -1) || (PLA->F == NULL) ){ /** MM: kontrola oboch chyb */
        kiss = oldkiss;
        fatal2("PLA couldn't be loaded");
        return -1;
    }

    /* This hack merges the next-state field with the outputs */
    /** MM: len upravuje hodnoty v cube->num_vars na kladne */
    for(i = 0; i < cube->num_vars; i++) {
    	cube->part_size[i] = ABS(cube->part_size[i]);
    }
    /** MM: podla dokumentacie je kiss "Sets up a kiss-style minimization problem. This is a hack." [commandline option]*/
    if (kiss) {
        third = cube->num_vars - 3;
        second = cube->num_vars - 2;
        if (cube->part_size[third] != cube->part_size[second]) {
            fatal2(" with .kiss option, third to last and second\nto last variables must be the same size.\n");
            kiss = oldkiss;
            return -1;
        }
        /** MM: ak je chybne zadany parameter -ekiss; vychodzie boli hodnoty ukazatelov v "kiss.pla" */
		if(PLA->label[cube->first_part[second]] != NULL || PLA->label[cube->first_part[third]] == NULL){
			fatal2("this is not a kiss styled PLA");
			kiss = oldkiss;
			return -1;
		}
    	for(i = 0; i < cube->part_size[second]; i++) {
            PLA->label[i + cube->first_part[second]] =
            util_strsav(PLA->label[i + cube->first_part[third]]);
        }
        /** MM: nejaka magia so zmenou velkosti alokovanej pamati pre kocku */
        cube->part_size[second] += cube->part_size[cube->num_vars-1];
        /** MM: zrusia sa nejake data; part_size sa nezmeni */
        setdown_cube();
        cube->num_vars--; /** MM: oprava memory leaku: najskor setdown a az potom uprava num_vars!!! */
        /** MM: kocka sa opat dostane do konzistentneho stavu */
        tmp = cube_setup();
        if (tmp == -1) { /** MM: chyba inicializacie kocky */
            kiss = oldkiss;
			return -1;
        }
    }
    kiss = oldkiss; /* MM: obvova povodneho kiss, aby sa mohol nacitat dalsi obvod podla povodnych nastaveni */

    /** MM: ak sa traceuje, vypise statistiku */
    if (trace) {
	   totals(time, READ_TIME, PLA->F, &cost);
    }

    /** MM: povodne tu bola cast dopocitavajuca SETy */

//	/** MM: povodne tomu predchadzala vetva s "pos" */
//	/* Check for phase rearrangement of the functions */
//    if (PLA->phase != NULL) { 
//		/** MM: set_phase modifikuje ON a OFF set; treba dopocitat OFF-set!!! */
//		if (PLA->pla_type==F_type || PLA->pla_type==FD_type) {
//			free_cover(PLA->R);
//			PLA->R = complement(cube2list(PLA->F, PLA->D));
//			if (PLA->R == NULL){ /** MM: ak chyba alokacie */
//				return -1; /** MM: ak chyba alokacie v complement */
//			}
//			/* treba upravit typ, aby sa to vypocitavalo len raz */
//			PLA->pla_type |= R_type;
//		} 
//        tmpPLA = set_phase(PLA);
//        if (tmpPLA==NULL) return -1; /** MM: ak chyba alokacie v set_phase */
//        
//    }

    /* Setup minimization for two-bit decoders */
//    if (PLA->pair != (ppair) NULL) {
//        tmp = set_pair(PLA);
//        if (tmp == -1) return -1; /** MM: ak chyba v set_pair */
//    }
//
//    if (PLA->symbolic != NIL(symbolic_t)) {
//        EXEC(tmp = map_symbolic(PLA), "MAP-INPUT  ", PLA->F);
//        if (tmp != 0) return -1; /** MM: ak chyba v map_symbolic*/ 
//    }
//    if (PLA->symbolic_output != NIL(symbolic_t)) {
//        EXEC(tmp = map_output_symbolic(PLA), "MAP-OUTPUT ", PLA->F);
//        if (tmp != 0) return -1; /** MM: ak chyba v map_output_symbolic */
//        /** MM: prepocitanie noveho off-setu? */
//        PLA->pla_type &= ~R_type; /** MM: toto zabezpeci prepocitanie OFF-setu, ak ho bude potreba */
//
//    }
    return 0;
}

/** MM: verzia pre string */
/** MM: posuva stringPtr */
static int read_symbolic_string(const char **stringPtr, pPLA PLA, char *word, symbolic_t **retval)  
           		                      /* word scratch string for words */
                    
{
    symbolic_list_t *listp, *prev_listp;
    symbolic_label_t *labelp, *prev_labelp;
    symbolic_t *newlist;
    int i, var;

    newlist = ALLOC(symbolic_t, 1);
    newlist->next = NIL(symbolic_t);
    newlist->symbolic_list = NIL(symbolic_list_t);
    newlist->symbolic_list_length = 0;
    newlist->symbolic_label = NIL(symbolic_label_t);
    newlist->symbolic_label_length = 0;
    prev_listp = NIL(symbolic_list_t);
    prev_labelp = NIL(symbolic_label_t);

    for(;;) {
    	(void) get_word_string(stringPtr, word);
    	if (str_equal(word, ";"))
    	    break;
    	if (label_index(PLA, word, &var, &i)) {
    	    listp = ALLOC(symbolic_list_t, 1);
    	    listp->variable = var;
    	    listp->pos = i;
    	    listp->next = NIL(symbolic_list_t);
    	    if (prev_listp == NIL(symbolic_list_t)) {
                newlist->symbolic_list = listp;
    	    } else {
        		prev_listp->next = listp;
    	    }
    	    prev_listp = listp;
    	    newlist->symbolic_list_length++;
    	} else {
    	    return FALSE3;
    	}
    }

    for(;;) {
    	(void) get_word_string(stringPtr, word);
    	if (str_equal(word, ";"))
    	    break;
    	labelp = ALLOC(symbolic_label_t, 1);
    	labelp->label = util_strsav(word);
    	labelp->next = NIL(symbolic_label_t);
    	if (prev_labelp == NIL(symbolic_label_t)) {
    	    newlist->symbolic_label = labelp;
    	} else {
    	    prev_labelp->next = labelp;
    	}
    	prev_labelp = labelp;
    	newlist->symbolic_label_length++;
    }

    *retval = newlist;
    return TRUE3;
}
