/* =========================================================================
 * Από: migf1
 * Πρόγραμμα παρουσίασης απλών λειτουργιών σε πίνακα, γραμμένο σε C.
 * =========================================================================
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_ELEMENTS		10			// μέγιστο πλήθος στοιχείων
#define EMPTY_ELEMVAL		(-1)			// τιμή κενών στοιχείων

#define MAX_INBUF		256			// μέγιστο μήκος γραμμής εισόδου

#define MAX_COMMANDS		11			// μέγιστο πληθος εντολών
#define MAX_CMDLEN		(5+1)			// μέγιστο μήκος εντολής
#define MAX_TOKENS		(MAX_ELEMENTS+1)	// μέγιστο πλήθος παραμέτρων σε
							// μια εντολή + την εντολή
	
#define SET_ISEMPTY(set)	( (set).len == 0 )	// έλέγχος για κενή λίστα
							// έλέγχος για γεμάτη λίστα
#define SET_ISFULL(set)		( (set).len == (set).maxlen )

typedef enum { FALSE=0, TRUE } Bool;			// ο δικός μας τύπος boolean

typedef enum {						// κωδικοί εντολών
	CMD_INVALID = -1,
	CMD_INS_APPEND,
	CMD_INS_PREPEND,
	CMD_INS_ASCEND,
	CMD_INS_DESCEND,
	CMD_DELETE,
	CMD_SRT_ASCEND,
	CMD_SRT_DESCEND,
	CMD_RESET,
	CMD_PRINT,
	CMD_HELP,
	CMD_EXIT
}CmdIndex;

typedef struct set {					// δομή για τη λίστα ακεραίων
	int maxlen;					// μέγιστο μήκος λίστας
	int len;					// τρέχον μήκος λίστας
	int elem[MAX_ELEMENTS];				// η λίστα (πίνακας)
} Set;

// -------------------------------------------------------------------------------------
// Διάσπαση του c-string s σε έως maxtokens τμήματα, κι αποθήκευσή τους στον πίνακα
// tokens (η διάσπαση γίνεται σύμφωνα με οποιονδήποτε από του χαρακτήρες στο c-string
// delimiters). Επιστρέφει το πλήθος των τμημάτων που προέκυψαν από την διάσπαση.
// -------------------------------------------------------------------------------------
int s_tokenize(char *s, char *tokens[], const int maxtokens, const char *delimiters)
{
	register int i=0;

	tokens[0] = strtok(s, delimiters);
	if (tokens[0] == NULL)
		return 0;
	for (i=1; i < maxtokens && (tokens[i]=strtok(NULL, delimiters)) != NULL; i++)
		; 

	return i;
}
// -------------------------------------------------------------------------------------
// Μετατροπή εντολής από c-string σε κωδικό εντολής (επιστρέφει τον κωδικό της εντολής)
// ΣΗΜΑΝΤΙΚΟ:
//	ο κωδικός εντολής ισοδυναμεί με τη θέση της στον πίνακα των εντολών (δείτε
//	στην αρχή της main() )
// -------------------------------------------------------------------------------------
CmdIndex cmd_getindex( const char *cmd, const char *commands[], const int maxcommands )
{
	register int i;
	for (i=0; i < maxcommands && strcmp(cmd, commands[i]); i++)
		;
	return i == maxcommands ? -1 : i;
}
// -------------------------------------------------------------------------------------
// Διάβασμα γραμμής εισόδου, διάσπασή της σε εντολή με παραμέτρους κι αποθήκευσή τους
// στον πίνακα tokens[] (επιστρέφει τον κωδικό της εντολής)
// -------------------------------------------------------------------------------------
int get_input( int *ntokens, char *tokens[], const int maxtokens, const char *commands[], const int maxcommands)
{
	char inbuf[ MAX_INBUF ] = "";		// η γραμμή εισόδου
	CmdIndex cmdcode;			// κωδικός εντολής

	do {
		cmdcode = CMD_INVALID;		// αρχικοποίηση
		printf("> ");			// εμφάνιση prompt
		fgets(inbuf, MAX_INBUF, stdin);	// διάβασμα γραμμής εισόδου
						// διάσπαση σε εντολή & παραμέτρους
		*ntokens = s_tokenize(inbuf, tokens, maxtokens, "\t \n");
		if ( *ntokens > 0 )		// μετατροπήυ σε κωδικό εντολής
			cmdcode = cmd_getindex(tokens[0], commands, maxcommands);
		if (cmdcode == CMD_INVALID)	// ανύπαρκτη εντολή
			puts("\tunrecognized command\n");
	} while( cmdcode == CMD_INVALID);	// απαίτηση υπαρκτής εντολής

	return cmdcode;				// επιστροφή κωδικού εντολής
}
// -------------------------------------------------------------------------------------
// Αρχικοποίηση της λίστας
// -------------------------------------------------------------------------------------
void set_init( Set *set )
{
	register int i;

	set->maxlen = MAX_ELEMENTS;
	for (i=0; i < set->maxlen; i++)
		set->elem[i] = EMPTY_ELEMVAL;
	set->len = 0;

	return;
}
// -------------------------------------------------------------------------------------
// Εμφάνιση όλων των στοιχείων της λίστας (επιστρέφει FALSE αν η λίστα είναι κενή,
// αλλιώς επιστρέφει TRUE)
// -------------------------------------------------------------------------------------
Bool set_print( Set set )
{
	register int i;
	for (i=0; i < set.len; i++)
		printf("%d ", set.elem[i] );

	return i == 0 ? FALSE : TRUE;
}
// -------------------------------------------------------------------------------------
// Επιστρέφει 0 αν τα n1 και n2 είναι ίσα, 1 αν το n1 > n2 ή -1 αν το n1 < n2
// ( χρησιμοποιείται στη στάνταρ συνάρτηση qsort() παρακάτω )
// -------------------------------------------------------------------------------------
int set_elemcmp(const void *n1, const void *n2)
{
  const int *a = (const int *) n1;
  const int *b = (const int *) n2;

  return (*a > *b) - (*a < *b);
}
// -------------------------------------------------------------------------------------
// Εισαγωγή νέου στοιχείου με τιμή val στο τέλος της λίστας (επιστρέφει είτε τη
// θέση στην οποία εισήχθη το νέο στοιχειο, είτε -1 σε περίπτωση που η λίστα ήταν
// ήδη γεμάτη, είτε -2 αν η τιμή val ισούται με την τιμή μηδενισμού EMPTY_ELEMVAL)
// -------------------------------------------------------------------------------------
int set_append( Set *set, const int val )
{
	if ( val == EMPTY_ELEMVAL )			// η μηδενική τιμή δεν εισάγεται
		return -2;				// επιστροφή αποτυχίας

	if ( SET_ISFULL(*set) )				// σε γεμάτο πίνακα...
		return -1;				// επιστροφή αποτυχίας

	set->elem[ set->len ] = val;
	return (set->len)++;				// επιστροφή θέσης εισαγωγής
}
// -------------------------------------------------------------------------------------
// Εισαγωγή νέου στοιχείου με τιμή val στην αρχή της λίστας (επιστρέφει είτε 0 σε
// περίπτωση που η λίστα ήταν ήδη γεμάτη, ειτε -1 αν η τιμή val ισούται με την τιμή
// μηδενισμού EMPTY_ELEMVAL, είτε 1 αν όλα πήγαν καλά)
// -------------------------------------------------------------------------------------
int set_prepend( Set *set, const int val )
{
	if ( val == EMPTY_ELEMVAL )			// η μηδενική τιμή δεν εισάγεται
		return -1;				// επιστροφή αποτυχίας

	if ( SET_ISFULL(*set) )				// σε γεμάτη λίστα
		return 0;				// επιστροφή αποτυχίας

	if ( SET_ISEMPTY(*set) ) {			// σε κενή λίστα
		set->elem[0] = val;			// εισαγωγή νέου στοιχείου
		(set->len)++;				// ενημέρωση τρέχοντος μήκους
		return 1;				// επιστροφή επιτυχίας
	}

	// μετακίνηση των στοιχείων μια θέση προς τα δεξιά, ξεκινώντας από το 1ο
	memmove( &(set->elem[1]), &(set->elem[0]), (set->len) * sizeof(int) );
	set->elem[0] = val;				// εισαγωγή νέου στοιχείου
	(set->len)++;					// ενημέρωση τρέχοντος μήκους

	return 1;					// επιστροφή επιτυχίας
}
// -------------------------------------------------------------------------------------
// Εισαγωγή νέου στοιχείου με τιμή val απευθείας στη σωστή θέση, σε λίστα που είναι
// ήδη ταξινομημένη με αύξουσα σειρά
// -------------------------------------------------------------------------------------
int set_insascend( Set *set, const int val )
{
	if ( val == EMPTY_ELEMVAL )			// η μηδενική τιμή δεν εισάγεται
		return -2;				// επιστροφή αποτυχίας

	if ( SET_ISFULL(*set) )				// σε γεμάτη λίστα
		return -1;				// επιστροφή αποτυχίας

	if ( SET_ISEMPTY(*set) ) {			// σε κενή λίστα...
		set->elem[0] = val;			// εισαγωγή στην αρχή της
		set->len = 1;				// ενημέρωση τρέχοντος μήκους
		return 0;				// επιστροφή 1ης θέσης
	}

	register int i;
	for (i=0; val > set->elem[i] && i < set->len; i++)
		;
	// μετακίνηση των στοιχείων μια θέση προς τα δεξιά, ξεκινώντας από το στοιχείο i
	memmove( &(set->elem[i+1]), &(set->elem[i]), (set->len-i) * sizeof(int) );

	set->elem[i] = val;				// εισαγωγή νέου στοιχείου
	(set->len)++;					// ενημέρωση τρέχοντος μήκους

	return i;					// επιστροφή θέσης εισαγωγής
}
// -------------------------------------------------------------------------------------
// Εισαγωγή νέου στοιχείου με τιμή val απευθείας στη σωστή θέση, σε λίστα που είναι
// ήδη ταξινομημένη με φθίνουσα σειρά
// -------------------------------------------------------------------------------------
int set_insdescend( Set *set, const int val )
{
	if ( val == EMPTY_ELEMVAL )			// η μηδενική τιμή δεν εισάγεται
		return -2;				// επιστροφή αποτυχίας

	if ( SET_ISFULL(*set) )				// σε γεμάτη λίστα
		return -1;				// επιστροφή αποτυχίας

	if ( SET_ISEMPTY(*set) ) {			// σε κενή λίστα...
		set->elem[0] = val;			// εισαγωγή στην αρχή της
		set->len = 1;				// ενημέρωση τρέχοντος μήκους
		return 0;				// επιστροφή 1ης θέσης
	}

	register int i;
	for (i=0; val < set->elem[i] && i < set->len; i++)
		;
	// μετακίνηση των στοιχείων μια θέση προς τα δεξιά, ξεκινώντας από το i στοιχείο
	memmove( &(set->elem[i+1]), &(set->elem[i]), (set->len-i) * sizeof(int) );

	set->elem[i] = val;				// εισαγωγή νέου στοιχείου
	(set->len)++;					// ενημέρωση τρέχοντος μήκους

	return i;					// επιστροφή θέσης εισαγωγής
}
// -------------------------------------------------------------------------------------
// Αναζήτηση του στοιχείου με τιμή val στη λίστα (επιστρέφει τη θέση στην οποία
// βρέθηκε το στοιχείο, αλλιώς επιστρέφει -1)
// -------------------------------------------------------------------------------------
int set_elemindex( const Set *set, const int val )
{
	if ( SET_ISEMPTY(*set) || val == EMPTY_ELEMVAL )
		return -1;

	register int i;
	for (i=0; set->elem[i] != val && i < set->len; i++)
		;
	return i == set->len ? -1 : i;	// τέλειωσαν τα στοιχεία ? -1 αλλιώς i		
}
// ------------------------------------------------------------------------------------
// Διαγραφή του στοιχείου με τιμή val από τη λίστα (επιστρέφει FALSE αν το στοιχείο
// δεν βρέθηκε στη λίστα, αλλιώς το διαγράφει κι επιστρέφει TRUE)
// -------------------------------------------------------------------------------------
Bool set_delete( Set *set, const int val )
{
	register int i;
							// εύρεση στοιχείου με τιμή val
	int elem = set_elemindex( set, val);
	if ( elem == -1 )				// το στοιχείο δεν βρέθηκε...
		return FALSE;				// επιστροφή αποτυχίας

	// μετακίνηση στοιχείων μια θέση προς τα αριστερά,
	// ξεκινώντας από τη θέση που βρέθηκε το στοιχείο
	for (i=elem; set->elem[i+1] != EMPTY_ELEMVAL && i < set->len-1; i++)
		set->elem[i] = set->elem[i+1];

	set->elem[i] = EMPTY_ELEMVAL;	// μηδενισμός του τέως τελευταίου στοιχείου 
	(set->len)--;					// ενημέρωση τρέχοντος μήκους

	return TRUE;					// επιστροφή επιτυχίας
}
// -------------------------------------------------------------------------------------
// Ταξινόμηση σε φθίνουσα σειρά των στοιχείων του πίνακα elem, ξεκινώντας από το στοιχείο
// lo έως το στοιχείο hi (η ταξινόμηση γίνεται με απλή υλοποίηση του αναδρομικού
// αλγόριθμου quick-sort)
// -------------------------------------------------------------------------------------
void qsort_descend(int elem[], int lo, int hi )
{
	int i=lo, j=hi, temp;
	int pivot = elem[ (lo+hi)/2 ];			// επιλογή του στοιχείου pivot

	do {						// διάσπαση του πίνακα
		while (elem[i] > pivot)
			i++; 
		while (elem[j] < pivot)
			j--;
		if ( i <= j)
		{
			temp = elem[i];
			elem[i] = elem[j];
			elem[j] = temp;
			i++;
			j--;
		}
	} while (i <= j);

	if (lo < j)					// αναδρομή
		qsort_descend(elem, lo, j);
	if (i < hi)
		qsort_descend(elem, i, hi);

	return;
}
// -------------------------------------------------------------------------------------
// Εμφάνιση του μενού των εντολών
// -------------------------------------------------------------------------------------
void do_help( const char *commands[] )
{
	puts("\nA R R A Y S\n");
	printf("SAMPLE OPERATIONS ON A LIST OF %d ELEMENTS\n", MAX_ELEMENTS);
	puts("------------------------------------------");
	printf("%s n1 n2 ...\tappend (up to %d numbers)\n", commands[0], MAX_ELEMENTS);
	printf("%s n1 n2 ...\tprepend(up to %d numbers)\n", commands[1], MAX_ELEMENTS);
	printf("%s  n1 n2 ...\tinsert in ascending  order\n", commands[2]);
	printf("%s  n1 n2 ...\tinsert in descending order\n", commands[3]);
	printf("%s   n\t\tdelete n\n", commands[4]);
	printf("%s \t\tsort in ascending order\n", commands[5]);
	printf("%s \t\tsort in descending order\n", commands[6]);
	printf("%s \t\treset\n", commands[7]);
	printf("%s \t\tprint\n", commands[8]);
	printf("%s \t\thelp\n", commands[9]);
	printf("%s \t\texit\n", commands[10]);
	puts("------------------------------------------");
	puts("   ONLY POSITIVE INTEGERS ARE ALLOWED");
	puts("------------------------------------------");

	return;
}
// -------------------------------------------------------------------------------------
// Εκτέλεση της εντολής "app n1 n2 ..."  που εισαγάγει τα n1 n2 ... στο τέλος της λίστας
// (επιστρέφει FALSE σε περίπτωση σφάλματος, αλλιώς επιστρέφει TRUE)
// -------------------------------------------------------------------------------------
Bool do_append( const int ntokens, char *tokens[], Set *set )
{
	if ( ntokens < 2 ) {				// ελλιπείς παράμετροι
		puts("\tspecify what to append\n");	// ...
		return FALSE;				// επιστροφή αποτυχίας
	}

	Bool warn1=FALSE, warn2=FALSE;
	register int i, temp, val;

	for (i=1; i < ntokens; i++)			// για κάθε n1, n2, ...
	{						// ...
		val = atoi( tokens[i] );		// μετατροπή σε ακέραιο
		if ( val < 0 ) {			// αρνητική τιμή...
			warn2 = TRUE;			// ενεργοποίηση προειδοποίησης #2
			continue;
		}

		temp = set_append( set, val );		// εισαγωγή νέου στοιχείου

		if ( temp == -2 )			// ήταν τιμή μηδενισμού...
			warn1 = TRUE;			// ενεργοποίηση προειδοποίησης #1
		else if ( temp == -1 ) {		// η λίστα ήταν γεμάτη...
			printf("\t%d was not appended (array is full)\n", val);
			return FALSE;			// επιστροφή αποτυχίας
		}
	}

	if ( warn1 )					// τύπωμα προειδοποίησης #1
		printf(	"\t(values equal to the zero-value: %d were ignored)\n",
			EMPTY_ELEMVAL);
	if ( warn2 )					// τύπωμα προειδοποίησης #2
		puts("\t(negative values were ignored)");

	return TRUE;					// επιστροφή επιτυχίας
}

// -------------------------------------------------------------------------------------
// Εκτέλεση της εντολής "pre n1 n2 ..."  που εισαγάγει τα n1 n2 ... στην αρχή της λίστας
// (επιστρέφει FALSE σε περίπτωση σφάλματος, αλλιώς επιστρέφει TRUE)
// -------------------------------------------------------------------------------------
Bool do_prepend( const int ntokens, char *tokens[], Set *set )
{
	if ( ntokens < 2 ) {				// ελλιπείς παράμετροι
		puts("\tspecify what to prepend\n");	// ...
		return FALSE;				// επιστροφή αποτυχίας
	}

	Bool warn1=FALSE, warn2=FALSE;
	register int i, temp, val;

	for (i=1; i < ntokens; i++)			// για κάθε n1, n2, ...
	{						// ...
		val = atoi( tokens[i] );		// μετατροπή σε ακέραιο
		if ( val < 0 ) {			// αρνητική τιμή...
			warn2 = TRUE;			// ενεργοποίηση προειδοποίησης #2
			continue;
		}

		temp = set_prepend( set, val );		// εισαγωγή νέου στοιχείου

		if ( temp == -1 )			// ήταν τιμή μηδενισμού...
			warn1 = TRUE;			// ενεργοποίηση προειδοποίησης #1
		else if ( temp == 0 ) {			// η λίστα ήταν γεμάτη...
			printf("\t%d was not prepended (array is full)\n", val);
			return FALSE;			// επιστροφή αποτυχίας
		}
	}

	if ( warn1 )					// τύπωμα προειδοποίησης #1
		printf(	"\t(values equal to the zero-value: %d were ignored)\n",
			EMPTY_ELEMVAL);
	if ( warn2 )					// τύπωμα προειδοποίησης #2
		puts("\t(negative values were ignored)");

	return TRUE;					// επιστροφή επιτυχίας
}
// -------------------------------------------------------------------------------------
// Εκτέλεση της εντολής "id n1 n2 ..."  που εισαγάγει τα n1 n2 ... στη λίστα,
// ταξινομημένα σε αύξουσα σειρά (επιστρέφει FALSE σε περίπτωση σφάλματος,
// αλλιώς επιστρέφει TRUE)
// -------------------------------------------------------------------------------------
Bool do_insascend( const int ntokens, char *tokens[], Set *set )
{
	if ( ntokens < 2 ) {				// ελλιπείς παράμετροι
		puts("\tspecify what to insert\n");	// ...
		return FALSE;				// επιστροφή αποτυχίας
	}

	Bool warn1=FALSE, warn2=FALSE;
	register int i, temp, val;

	for (i=1; i < ntokens; i++)			// για κάθε n1, n2, ...
	{						// ...
		val = atoi( tokens[i] );		// μετατροπή σε ακέραιο
		if ( val < 0 ) {			// αρνητική τιμή...
			warn2 = TRUE;			// ενεργοποίηση προειδοποίησης #2
			continue;
		}

		temp = set_insascend( set, val );	// εισαγωγή νέου στοιχείου

		if ( temp == -2 )			// ήταν τιμή μηδενισμού...
			warn1 = TRUE;			// ενεργοποίηση προειδοποίησης #1
		else if ( temp == -1 ) {		// η λίστα ήταν γεμάτη...
			printf("\t%d was not inserted (array is full)\n", val);
			return FALSE;			// επιστροφή αποτυχίας
		}
	}

	if ( warn1 )					// τύπωμα προειδοποίησης #1
		printf(	"\t(values equal to the zero-value: %d were ignored)\n",
			EMPTY_ELEMVAL);
	if ( warn2 )					// τύπωμα προειδοποίησης #2
		puts("\t(negative values were ignored)");

	return TRUE;					// επιστροφή επιτυχίας
}
// -------------------------------------------------------------------------------------
// Εκτέλεση της εντολής "id n1 n2 ..."  που εισαγάγει τα n1 n2 ... στη λίστα,
// ταξινομημένα σε φθίνουσα σειρά (επιστρέφει FALSE σε περίπτωση σφάλματος,
// αλλιώς επιστρέφει TRUE)
// -------------------------------------------------------------------------------------
Bool do_insdescend( const int ntokens, char *tokens[], Set *set )
{
	if ( ntokens < 2 ) {				// ελλιπείς παράμετροι
		puts("\tspecify what to insert\n");	// ...
		return FALSE;				// επιστροφή αποτυχίας
	}

	Bool warn1=FALSE, warn2=FALSE;
	register int i, temp, val;

	for (i=1; i < ntokens; i++)			// για κάθε n1, n2, ...
	{						// ...
		val = atoi( tokens[i] );		// μετατροπή σε ακέραιο
		if ( val < 0 ) {			// αρνητική τιμή...
			warn2 = TRUE;			// ενεργοποίηση προειδοποίησης #2
			continue;
		}

		temp = set_insdescend( set, val );	// εισαγωγή νέου στοιχείου

		if ( temp == -2 )			// ήταν τιμή μηδενισμού...
			warn1 = TRUE;			// ενεργοποίηση προειδοποίησης #1
		else if ( temp == -1 ) {		// η λίστα ήταν γεμάτη...
			printf("\t%d was not inserted (array is full)\n", val);
			return FALSE;			// επιστροφή αποτυχίας
		}
	}

	if ( warn1 )					// τύπωμα προειδοποίησης #1
		printf(	"\t(values equal to the zero-value: %d were ignored)\n",
			EMPTY_ELEMVAL);
	if ( warn2 )					// τύπωμα προειδοποίησης #2
		puts("\t(negative values were ignored)");

	return TRUE;					// επιστροφή επιτυχίας
}
// -------------------------------------------------------------------------------------
// Εκτέλεση της εντολής "d n1" που διαγράφει το n από τη λίστα (επιστρέφει FALSE σε
// περίπτωση σφάλματος, αλλιώς επιστρέφει TRUE)
// -------------------------------------------------------------------------------------
Bool do_delete( const int ntokens, char *tokens[], Set *set )
{
	if ( ntokens < 2 ) {				// ελλιπείς παράμετροι
		puts("\tspecify what to delete\n");	// ...
		return FALSE;				// επιστροφή αποτυχίας
	}

	int val = atoi( tokens[1] );			// μετατροπή n σε ακέραιο
	if ( !set_delete( set, val ) )			// το στοιχείο δεν βρέθηκε
			printf("\t%d was not found\n", val);
	else						// επιτυχής διαγραφή στοιχείου
		printf("\t%d deleted successfully\n", val);

	return TRUE;					// επιστροφή επιτυχίας
}
// -------------------------------------------------------------------------------------
// Εκτέλεση της εντολής "p" που τυπώνει τα περιεχομενα της λίστας
// -------------------------------------------------------------------------------------
void do_print( Set set )
{
	printf("\tlist (%d) : ", set.len);
	if ( !set_print( set ) )
		puts("empty\n");
	else
		puts("\n");

	return;
}
// -------------------------------------------------------------------------------------
// Εκτέλεση της επιλεγμένης από τον χρήστη εντολής
// -------------------------------------------------------------------------------------
void do_command( const CmdIndex cmdcode, const char *commands[], const int ntokens, char *tokens[], Set *set )
{
	switch ( cmdcode )
	{
		case CMD_INS_APPEND:
			if ( do_append( ntokens, tokens, set ) )
				do_print( *set );
			break;

		case CMD_INS_PREPEND:
			if ( do_prepend( ntokens, tokens, set ) )
				do_print( *set );
			break;

		case CMD_INS_ASCEND:
			if ( do_insascend( ntokens, tokens, set ) )
				do_print( *set );
			break;

		case CMD_INS_DESCEND:
			if ( do_insdescend( ntokens, tokens, set ) )
				do_print( *set );
			break;

		case CMD_DELETE:
			if ( do_delete( ntokens, tokens, set ) )
				do_print( *set );
			break;

		case CMD_SRT_ASCEND:
			qsort( set->elem, set->len, sizeof(int), set_elemcmp);
			do_print( *set );
			break;

		case CMD_SRT_DESCEND:
			qsort_descend( set->elem, 0, set->len-1 );
			do_print( *set );
			break;

		case CMD_RESET:
			set_init( set );
			puts("\tarray was reset successfully\n");
			break;

		case CMD_PRINT:
			do_print( *set );
			break;

		case CMD_HELP:
			do_help( commands );
			break;
		default:
			break;
	}

	return;
}
// -------------------------------------------------------------------------------------
int main( void )
{
	const char *commands[MAX_COMMANDS ] = {		// πίνακας εντολών
		"app", "pre", "ia", "id", "d", "sa", "sd", "r", "p", "h", "x"
	};
	CmdIndex cmdcode;				// κωδικός επιλεγμένης εντολής
	char *tokens[ MAX_TOKENS ];			// παράμετροι εντολής + εντολή
	int ntokens;					// πλήθος εντολής + παραμέτρων
	Set set = { MAX_ELEMENTS, 0, {-1} };		// η λίστα μας

	set_init( &set );				// ΣΗΜΑΝΤΙΚΗ αρχικοποίηση
	do_help( commands );				// εμφάνιση μενού εντολών

	do {						// ανάγνωση εντολής
		cmdcode = get_input( &ntokens, tokens,MAX_TOKENS, commands,MAX_COMMANDS);
							// εκτέλεση εντολής
		do_command(cmdcode, commands, ntokens, tokens, &set);
	} while( cmdcode != CMD_EXIT );

	exit( EXIT_SUCCESS );				// επιτυχής τερματισμός
}

