/// =========================== LIBRERIA STRCONS =========================== ///
/// di Aldo Carpanelli ///
/// v1.1, 13/11-6/12 2016 ///
/// ======================================================================== ///
#include "stringa_console.h"
/// ===> variabili statiche <=============================================== ///
static char *STRCONS_buffer = NULL;
static size_t STRCONS_capacita = 0;
static size_t STRCONS_lunghezza = 0;
/// ===> gestione degli errori <============================================ ///
// Una stringa descrittiva per ciascuno dei
// codici d'errore enumerati in stringa_console.h
const char *STRCONSErr_d[STRCONSErr_MaxIndStrErr] = {
"l'input e' una stringa vuota",
"buffer insufficiente, input troncato",
"nessun errore",
"memoria non allocata",
"e' stato richiesto un buffer di 4GB o piu'",
"errore in fgets()",
"la stringa non rappresenta un numero"
};
const char *STRCONSErr_Descrizione( int codice ) {
if( codice >= STRCONSErr_no_str &&
codice < STRCONSErr_MaxIndStrErr )
return STRCONSErr_d[codice+2];
else return "errore non previsto";
}
/// ===> inizializzazione e dismissione <=================================== ///
/*==============================================================================
Inizializza la libreria, allocando un buffer che puo' contenere un massimo di
dim caratteri (il buffer finisce quindi per avere dimensioni pari a dim+1
bytes). Al momento dell'allocazione, il buffer contiene una serie di '\0'.
La libreria viene inizializzata in modo che il buffer abbia una dimensione
minima di 31 caratteri.
Qualora l'allocazione della memoria necessaria non fosse possibile,
l'inizializzazione fallirebbe e verrebbe restituito un codice di errore.
==============================================================================*/
int STRCONS_Inizializza( size_t dim ) {
dim = dim>1 ? dim : 2;
return STRCONS_Dimensiona( dim );
}
/*==============================================================================
Si occupa di liberare la memoria allocata per il buffer abbinato alla libreria.
==============================================================================*/
void STRCONS_Dismetti( void ) {
if( STRCONS_buffer ) {
free( STRCONS_buffer );
STRCONS_buffer = NULL;
}
STRCONS_capacita = STRCONS_lunghezza = 0;
}
/// ===> modifica dello stato della libreria <============================== ///
/*==============================================================================
Cambia le dimensioni del buffer, prevedendo lo spazio per il terminatore '\0'
(dunque, vengono allocati dim+1 byte di memoria).
Se il buffer contiene gia' dei dati, i dati gia' presenti vengono conservati
(nei limiti del possibile).
Se non e' possibile modificare le dimensioni del buffer, il vecchio buffer viene
conservato, cosi' come il suo contenuto.
In caso d'insuccesso restituisce un codice di errore che puo' essere usato per
ricavare informazioni sul tipo di problema riscontrato. Il codice di errore puo'
essere...
STRCONSErr_enorme e' stata richiesta l’allocazione di un buffer dalle
dimensioni uguali o superiori a 4GB, il che e' un'assurdita'
STRCONSErr_no_mem l'allocazione della memoria e' fallita; il buffer non e'
stato ridimensionato, ma il suo contenuto originale e'
rimasto intatto
STRCONSErr_no_err tutto bene, il buffer e' stato ridimensionato e le parti
conservabili del suo contenuto sono state conservate
==============================================================================*/
int STRCONS_Dimensiona( size_t dim ) {
if( dim >= 0xFFFFFFFF ) return STRCONSErr_enorme; // buffer insensato (2)
dim = dim>1 ? dim : 2;
char *tmp = (char*) calloc( dim+1, sizeof(char) );
if( tmp == NULL ) return STRCONSErr_no_mem; // memoria insufficiente (1)
size_t i, usati = dim<STRCONS_lunghezza ? dim : STRCONS_lunghezza;
if( STRCONS_buffer != NULL ) {
for( i=0; i<usati; ++i )
tmp[i] = STRCONS_buffer[i];
free( STRCONS_buffer );
}
STRCONS_buffer = tmp;
STRCONS_capacita = dim;
STRCONS_lunghezza = usati;
return STRCONSErr_no_err; // tutto bene (0)
}
/*==============================================================================
Chiede tramite console di inserire un testo. Il testo viene letto fino a un
massimo di caratteri corrispondenti all'attuale capacita' massima del buffer
(impostata tramite STRCONS_Inizializza() oppure STRCONS_Dimensiona()).
Al termine dell'immissione svuota gli eventuali caratteri "pendenti" nello
stdin, "consumandoli" per mezzo di ripetute chiamate a fgets() con un buffer
ausiliario di 2 byte.
In caso d'insuccesso restituisce un codice di errore che puo' essere usato per
ricavare informazioni sul tipo di problema riscontrato. Il codice di errore puo'
essere...
STRCONSErr_no_str l'utente ha premuto invio senza immettere alcun testo; il
buffer contiene solo il carattere terminatore (cioe' una
stringa vuota e niente piu')
STRCONSErr_troncato la stringa immessa in console e' parzialmente presente nel
buffer, terminata da '\0'; la parte eccedente le dimensioni
del buffer e' andata persa
STRCONSErr_no_err tutto bene, la stringa immessa in console e' presente nel
buffer (senza il carattere finale '\n'), terminata da '\0'
STRCONSErr_no_fgets c'e' stato un errore non meglio precisato nella chiamata
allafunzione standard fgets(); il buffer e' nella sua
condizione antecedente alla chiamata al metodo chiedi()
==============================================================================*/
int STRCONS_Chiedi( void ) {
if( fgets(STRCONS_buffer,STRCONS_capacita+1,stdin) != NULL ) {
size_t lung = strlen( STRCONS_buffer );
if( STRCONS_buffer[lung-1]=='\n' ) {
// il buffer contiene tutto l'input
STRCONS_lunghezza = STRCONS_EliminaNewline( STRCONS_buffer, lung );
if( STRCONS_lunghezza > 0 )
return STRCONSErr_no_err; // TUTTO BENE (0)
else return STRCONSErr_no_str; // stringa vuota (-2)
}
else { // il buffer potrebbe contenere solo parte dell'input
STRCONS_lunghezza = lung;
if( STRCONS_SvuotaStdin() == 0 )
// eccedeva solo '\n', l'input c'e' tutto
return STRCONSErr_no_err; // TUTTO BENE (0)
else // buffer insufficiente, input valido ma troncato
return STRCONSErr_troncato; // valore negativo (-1)
}
}
else {
return STRCONSErr_no_fgets; // errore in fgets() (3)
}
}
/// ===> informazioni sullo stato della libreria <========================== ///
/*==============================================================================
Fornisce informazioni sulla capacità massima del buffer della libreria (intesa
come numero di caratteri effettivamente ricevibili, escluso dunque il carattere
terminatore della stringa C).
==============================================================================*/
size_t STRCONS_Capacita( void ) {
return STRCONS_capacita;
}
/*==============================================================================
Fornisce informazioni sulla lunghezza della stringa C correntemente contenuta
nel buffer della libreria (sempre minore o uguale al valore restituito dal
metodo STRCONS _Capacita()).
==============================================================================*/
size_t STRCONS_Lunghezza( void ) {
return STRCONS_lunghezza;
}
/*==============================================================================
Fornisce un puntatore allo spazio di memoria riservato al buffer della libreria,
il che equivale a fornire l'indirizzo della stringa C in esso contenuta e
immessa dall'utente in console.
NOTA: e' essenziale che la memoria abbinata al puntatore restituito da questo
metodo non venga mai liberata direttamente - si usi sempre STRCONS_Dismetti().
==============================================================================*/
char *STRCONS_PStr( void ) {
return STRCONS_buffer;
}
/*==============================================================================
Converte la stringa contenuta nel buffer in un valore numerico, secondo la
notazione indicata tramite il parametro base.
Immette il risultato della conversione all'indirizzo passato come parametro in
l. Restituisce un codice di errore che puo' essere STRCONSErr_no_err (tutto
bene) oppure STRCONSErr_no_num (conversione non effettuata).
==============================================================================*/
int STRCONS_Long( long *l, int base ) {
char *p = STRCONS_buffer;
long tmp = strtol( STRCONS_buffer, &p, base );
if( p != STRCONS_buffer ) *l = tmp;
return p!=STRCONS_buffer ? STRCONSErr_no_err : STRCONSErr_no_num;
}
/*==============================================================================
Converte la stringa contenuta nel buffer in un valore numerico, secondo la
notazione indicata tramite il parametro base.
Immette il risultato della conversione all'indirizzo passato come parametro in
ul. Restituisce un codice di errore che puo' essere STRCONSErr_no_err (tutto
bene) oppure STRCONSErr_no_num (conversione non effettuata).
==============================================================================*/
int STRCONS_UnsignedLong( unsigned long *ul, int base ) {
char *p = STRCONS_buffer;
unsigned long tmp = strtoul( STRCONS_buffer, &p, base );
if( p != STRCONS_buffer ) *ul = tmp;
return p!=STRCONS_buffer ? STRCONSErr_no_err : STRCONSErr_no_num;
}
/*==============================================================================
Converte la stringa contenuta nel buffer in un valore numerico.
Immette il risultato della conversione all'indirizzo passato come parametro in
d. Restituisce un codice di errore che puo' essere STRCONSErr_no_err (tutto
bene) oppure STRCONSErr_no_num (conversione non effettuata).
==============================================================================*/
int STRCONS_Double( double *d ) {
char *p = STRCONS_buffer;
double tmp = strtod( STRCONS_buffer, &p );
if( p != STRCONS_buffer ) *d = tmp;
return p!=STRCONS_buffer ? STRCONSErr_no_err : STRCONSErr_no_num;
}
/// ===> funzioni accessorie <============================================== ///
/*==============================================================================
Elimina un carattere '\n' eventualmente presente in coda alla stringa puntata da
str. Restituisce la quantita' di caratteri presenti nella stringa dopo
l'elaborazione.
==============================================================================*/
size_t STRCONS_EliminaNewline( char *str, size_t lung ) {
if( str != NULL && lung > 0 )
str[--lung] = '\0'; // elimina il '\n'
return lung;
}
/*==============================================================================
Elimina gli eventuali caratteri "pendenti" nello stream stdin. In uscita,
restituisce la quantita' dei caratteri eliminati dallo stream (ad esclusione del
carattere '\n', che non viene conteggiato).
==============================================================================*/
size_t STRCONS_SvuotaStdin() {
char b2[2] = { '\0', '\0' };
size_t eliminati = 0;
while( *b2 != '\n' ) { // svuota lo stream di input
fgets( b2, 2, stdin );
eliminati += *b2 != '\n';
}
return eliminati;
}
/*==============================================================================
Sostituisce nel buffer ogni occorrenza dei caratteri ',' e '.' con il carattere
impostato come carattere decimale nella localizzazione corrente, rilevato
tramite la funzione standard localeconv().
==============================================================================*/
void STRCONS_AdattaPuntoDecimale( void ) {
char *p = STRCONS_buffer;
char v = *(localeconv()->decimal_point);
while( *p ) { *p=*p=='.'||*p==','?v:*p; ++p; }
}