Oppure

Loading
07/01/15 18:12
"Stuzzicato" da una discussione alla quale ho partecipato in un altro forum (in lingua inglese), ho messo insieme una piccola collezione di funzioni da hobbista. Nelle intenzioni, le funzioni dovrebbero fornire un modo preimpostato per caricare elementi da una stringa formattata secondo una specie di "csv della mutua".

Il formato leggibile è del tipo "elemento 1,elemento 2,elemento 3,elemento 4" e così via, dove "," può essere sostituito da qualunque carattere si desideri, purché rappresentabile tramite il tipo char.

Le funzioni che ho previsto sono (come da file d'intestazione items.h):

/**=============================================================================
Libreria "items" - version 1.0.0, 20150102
=============================================================================**/

#ifndef ITEMS_H_INCLUDED
#define ITEMS_H_INCLUDED

long CountItemsInString( const char *data, int sep );
long CountItemsInFile( const char *fileName, int sep );

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs );
long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs );

char *GetItemFromString( const char *data, int sep, long nItem );
char *GetItemFromFile( const char *fileName, int sep, long nItem );

char *LoadFile( const char *fileName );
char *AllocateCopy( const char *s, long l );
void FreeStringMemory( char **s );
void FreeStringsMemory( const char ***ptrs );

#endif // ITEMS_H_INCLUDED


Le ultime quattro, in effetti, non sono molto utili (sono più che altro funzioni "di servizio" per le altre) ma le ho rese comunque accessibili già che erano lì, fatte e finite.

Siccome non sono certo un esperto, chiedo a chi avesse voglia di dare un'occhiata all'implementazione se sono realizzate in un modo sensato oppure no. Per quel che ne so, si compilano a dovere e non hanno creato problemi nei test, ma non si sa mai. Il file items.c è in allegato, non lo copio/incollo perché è troppo lungo.

Per onestà, vi dirò che circa una settimana fa ho posto la stessa domanda nel forum in inglese che citavo poco sopra, ma più che delle opinioni sulla correttezza ed efficacia del codice e/o dell'algoritmo ho ricevuto dei rimbrotti per ragioni che non ho ben capito (pare che mi si rimproverasse di non aver voglia d'imparare... mah...).

Ovviamente nessuno è costretto a rispondermi, ci mancherebbe altro, ma apprezzerei se qualcuno lo facesse.
Ultima modifica effettuata da 07/01/15 18:13
07/01/15 18:26
Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.



/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
'. Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad allocare memoria, il valore di ritorno e' NULL. ==============================================================================*/ char *LoadFile( const char *fileName ) { char *auxPtr, *data = NULL; long dataDim; int c; FILE *f; if( fileName == NULL ) return data; if( *fileName == 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
' ) return data; f = fopen( fileName, "r" ); if( f == NULL ) return data; for( dataDim=0; fgetc(f)!=EOF; ++dataDim ); data = malloc( dataDim+1 ); if( data != NULL ) { rewind( f ); auxPtr = data; while( (c=fgetc(f))!=EOF ) *auxPtr++ = c; *auxPtr = 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
'; } fclose( f ); return data; } /*============================================================================== Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare la memoria dinamica allocata appena non ne ha piu' necessita'. ==============================================================================*/ char *AllocateCopy( const char *s, long l ) { long sl; // [s]tring [l]ength char *copy = NULL; if( s == NULL ) return copy; sl = l<0 ? strlen(s) : l; if( (copy=malloc(sl+1)) != NULL ) { memcpy(copy,s,sl); copy[sl]='Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
'; } return copy; } /*============================================================================== Restituisce la quantita' totale degli elementi contenuti nella stringa passata tramite il parametro data. Gli elementi vengono riconosciuti contando le ricorrenze del carattere passato tramite il parametro sep. ==============================================================================*/ long CountItemsInString( const char *data, int sep ) { long n; if( data == NULL ) return -1; for( n=1; *data; ++data ) if( *data == sep ) ++n; return n; } /*============================================================================== Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e' passato tramite il parametro fileName. Gli elementi vengono riconosciuti contando le ricorrenze del carattere passato tramite il parametro sep. ==============================================================================*/ long CountItemsInFile( const char *fileName, int sep ) { FILE *f; long n; int c; if( fileName == NULL ) return -1; if( *fileName == 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
' ) return -1; f = fopen( fileName, "r" ); if( f == NULL ) return -1; for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) ) if( c == sep ) ++n; fclose( f ); return n; } long TokeniseString( char *data, int sep, const char ***ptrs ) { const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */ const char *strtok_result; long totItems; char sp[2] = { sep, 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
' }; totItems = CountItemsInString( data, sep ); auxPtr = tap = calloc( totItems, sizeof(char*) ); if( tap == NULL ) return -1; for( strtok_result = strtok(data,sp); strtok_result != NULL; *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp)); *ptrs = tap; return totItems; } /*============================================================================== Carica tutti gli elementi dalla stringa passata tramite il parametro data, copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi vengono riconosciuti contando le ricorrenze del carattere passato tramite il parametro sep. ==============================================================================*/ long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) { long totItems = -1; char *copy; copy = AllocateCopy( data, -1 ); if( copy == NULL ) return -1; totItems = TokeniseString( copy, sep, ptrs ); if( totItems == -1 ) free( copy ); return totItems; } /*============================================================================== Carica tutti gli elementi contenuti nel file del quale viene passato il nome tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi vengono riconosciuti contando le ricorrenze del carattere passato tramite il parametro sep. ==============================================================================*/ long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) { long totItems = 0; char *data = NULL; if( fileName == NULL ) return -1; if( *fileName == 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
' ) return -1; data = LoadFile( fileName ); if( data == NULL ) return -1; totItems = TokeniseString( data, sep, ptrs ); if( totItems == -1 ) free( data ); return totItems; } /*============================================================================== Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore a char che viene restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le ricorrenze del carattere passato tramite il parametro sep. ==============================================================================*/ char *GetItemFromString( const char *data, int sep, long nItem ) { long ci; /* [c]urrent [i]tem */ char *strItem = NULL; char sp[2] = { sep, 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
' }; if( data == NULL ) return strItem; for( ci=0; (ci<nItem)&&(data=strchr(data,sep)); ++data, ++ci ); if( ci == nItem ) strItem = AllocateCopy( data, strcspn(data,sp) ); return strItem; } /*============================================================================== Carica dal file che ha per nome la stringa passata tramite il parametro data l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore a char che viene restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le ricorrenze del carattere passato tramite il parametro sep. ==============================================================================*/ char *GetItemFromFile( const char *fileName, int sep, long nItem ) { long i, start, length, c, ci; /* [c]urrent [i]tem */ char *strItem = NULL; FILE *f; if( fileName == NULL ) return strItem; if( *fileName == 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
' ) return strItem; f = fopen( fileName, "r" ); if( f == NULL ) return strItem; for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) ) if( c == sep ) ++ci; if( ci == nItem ) { start = ftell(f)-1; for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) ); length = ftell(f)-1-start; if( (strItem=malloc(length+1)) != NULL ) { fseek( f, start, SEEK_SET ); for( i=0; i<length; *(strItem+i)=fgetc(f), ++i ); *(strItem+i) = 'Bello... pare che per qualche ragione non vengano accettati gli allegati, per cui (con rammarico) provvedo a quel copia/incolla di dimensioni epiche che avrei voluto evitare.


/**=============================================================================
"items" library - version 1.0.0, 20150102
=============================================================================**/

#include "items.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>


/*==============================================================================
Apre un file come stream testuale, alloca memoria dinamica nella quantita'
opportuna e legge il testo in essa. La stringa risultante e' terminata da '{parsed_message}'.
Il chiamante deve liberare la memoria dinamica puntata dal valore di ritorno non
appena non e' piu' necessaria. Se la funzione non riesce ad aprire il file o ad
allocare memoria, il valore di ritorno e' NULL.
==============================================================================*/

char *LoadFile( const char *fileName ) {
    char *auxPtr, *data = NULL;
    long dataDim;
    int c;
    FILE *f;

    if( fileName == NULL ) return data;
    if( *fileName == '{parsed_message}' ) return data;

    f = fopen( fileName, "r" );
    if( f == NULL ) return data;

    for( dataDim=0; fgetc(f)!=EOF; ++dataDim );

    data = malloc( dataDim+1 );

    if( data != NULL ) {
        rewind( f );
        auxPtr = data;

        while( (c=fgetc(f))!=EOF )
            *auxPtr++ = c;
        *auxPtr = '{parsed_message}';
    }

    fclose( f );
    return data;
}


/*==============================================================================
Alloca memoria dinamica e copia in essa una stringa. Il chiamante deve liberare
la memoria dinamica allocata appena non ne ha piu' necessita'.
==============================================================================*/

char *AllocateCopy( const char *s, long l ) {
    long sl; // [s]tring [l]ength
    char *copy = NULL;

    if( s == NULL ) return copy;

    sl = l<0 ? strlen(s) : l;

    if( (copy=malloc(sl+1)) != NULL )
        { memcpy(copy,s,sl); copy[sl]='{parsed_message}'; }

    return copy;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nella stringa passata
tramite il parametro data. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInString( const char *data, int sep ) {
    long n;

    if( data == NULL ) return -1;

    for( n=1; *data; ++data )
        if( *data == sep ) ++n;

    return n;
}


/*==============================================================================
Restituisce la quantita' totale degli elementi contenuti nel file il cui nome e'
passato tramite il parametro fileName. Gli elementi vengono riconosciuti
contando le ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long CountItemsInFile( const char *fileName, int sep ) {
    FILE *f;
    long n;
    int c;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    f = fopen( fileName, "r" );
    if( f == NULL ) return -1;

    for( n=1, c=fgetc(f); c!=EOF; c=fgetc(f) )
        if( c == sep ) ++n;

    fclose( f );
    return n;
}


long TokeniseString( char *data, int sep, const char ***ptrs ) {
    const char **auxPtr, **tap; /* [t]emporary [a]rray of [p]ointers */
    const char *strtok_result;
    long totItems;
    char sp[2] = { sep, '{parsed_message}' };

    totItems = CountItemsInString( data, sep );

    auxPtr = tap = calloc( totItems, sizeof(char*) );
    if( tap == NULL ) return -1;

    for( strtok_result = strtok(data,sp);
         strtok_result != NULL;
         *auxPtr++=strtok_result, strtok_result=strtok(NULL,sp));

    *ptrs = tap;
    return totItems;
}


/*==============================================================================
Carica tutti gli elementi dalla stringa passata tramite il parametro data,
copiandoli nella memoria dinamica e restituendo il loro indirizzo sotto forma di
un array di puntatori a char. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

long GetAllItemsFromString( const char *data, int sep, const char ***ptrs ) {
    long totItems = -1;
    char *copy;

    copy = AllocateCopy( data, -1 );
    if( copy == NULL ) return -1;

    totItems = TokeniseString( copy, sep, ptrs );
    if( totItems == -1 ) free( copy );

    return totItems;
}


/*==============================================================================
Carica tutti gli elementi contenuti nel file del quale viene passato il nome
tramite il parametro fileName, copiandoli nella memoria dinamica e restituendo
il loro indirizzo sotto forma di un array di puntatori a char. Gli elementi
vengono riconosciuti contando le ricorrenze del carattere passato tramite il
parametro sep.
==============================================================================*/

long GetAllItemsFromFile( const char *fileName, int sep, const char ***ptrs ) {
    long totItems = 0;
    char *data = NULL;

    if( fileName == NULL ) return -1;
    if( *fileName == '{parsed_message}' ) return -1;

    data = LoadFile( fileName );
	if( data == NULL ) return -1;

    totItems = TokeniseString( data, sep, ptrs );
    if( totItems == -1 ) free( data );

    return totItems;
}


/*==============================================================================
Carica dalla stringa data l'elemento alla posizione indicata dal parametro nItem
(zero based), copiandolo nell'area della memoria dinamica puntata dal puntatore
a char che viene restituito come valore di ritorno. Gli elementi vengono
riconosciuti contando le ricorrenze del carattere passato tramite il parametro
sep.
==============================================================================*/

char *GetItemFromString( const char *data, int sep, long nItem ) {
    long ci; /* [c]urrent [i]tem */
    char *strItem = NULL;
    char sp[2] = { sep, '{parsed_message}' };

    if( data == NULL ) return strItem;

    for( ci=0;
         (ci<nItem)&&(data=strchr(data,sep));
         ++data, ++ci );

    if( ci == nItem )
        strItem = AllocateCopy( data, strcspn(data,sp) );

    return strItem;
}


/*==============================================================================
Carica dal file che ha per nome la stringa passata tramite il parametro data
l'elemento alla posizione indicata dal parametro nItem (zero based), copiandolo
nell'area della memoria dinamica puntata dal puntatore a char che viene
restituito come valore di ritorno. Gli elementi vengono riconosciuti contando le
ricorrenze del carattere passato tramite il parametro sep.
==============================================================================*/

char *GetItemFromFile( const char *fileName, int sep, long nItem ) {
    long i, start, length, c, ci; /* [c]urrent [i]tem */
	char *strItem = NULL;
    FILE *f;

    if( fileName == NULL ) return strItem;
    if( *fileName == '{parsed_message}' ) return strItem;

    f = fopen( fileName, "r" );
    if( f == NULL ) return strItem;

    for( ci=0, c=fgetc(f); ci!=nItem && c!=EOF; c=fgetc(f) )
        if( c == sep ) ++ci;

    if( ci == nItem ) {
        start = ftell(f)-1;
        for( c=fgetc(f); c!=sep&&c!=EOF; c=fgetc(f) );
        length = ftell(f)-1-start;

        if( (strItem=malloc(length+1)) != NULL ) {
            fseek( f, start, SEEK_SET );
            for( i=0; i<length; *(strItem+i)=fgetc(f), ++i );
            *(strItem+i) = '{parsed_message}';
        }
    }

    fclose( f );
    return strItem;
}


/*==============================================================================
Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro
s e imposta il puntatore in s su NULL (in altre parole, quando la funzione
ritorna, il contenuto di s e' NULL).
==============================================================================*/

void FreeStringMemory( char **s ) {
    if( *s!= NULL ) {
        free( (void*)*s );
        *s = NULL;
    }
}


/*==============================================================================
Libera la memoria allocata nello spazio dinamico dalla funzione
GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore
del contenuto di ptrs e' NULL.
==============================================================================*/

void FreeStringsMemory( const char ***ptrs ) {
    if( ptrs == NULL ) return;
    if( *ptrs == NULL ) return;

    if( **ptrs != NULL ) {
        free( (void*)(**ptrs) );
        **ptrs = NULL;
    }

    free( (void*)(*ptrs) );
    (*ptrs) = NULL;
}
'; } } fclose( f ); return strItem; } /*============================================================================== Questa e' banale. Libera la memoria dinamica puntata dal contenuto del parametro s e imposta il puntatore in s su NULL (in altre parole, quando la funzione ritorna, il contenuto di s e' NULL). ==============================================================================*/ void FreeStringMemory( char **s ) { if( *s!= NULL ) { free( (void*)*s ); *s = NULL; } } /*============================================================================== Libera la memoria allocata nello spazio dinamico dalla funzione GetItemsFromString() o dalla funzione GetItemsFromFile(). In uscita, il valore del contenuto di ptrs e' NULL. ==============================================================================*/ void FreeStringsMemory( const char ***ptrs ) { if( ptrs == NULL ) return; if( *ptrs == NULL ) return; if( **ptrs != NULL ) { free( (void*)(**ptrs) ); **ptrs = NULL; } free( (void*)(*ptrs) ); (*ptrs) = NULL; }
Ultima modifica effettuata da 07/01/15 18:35
07/01/15 19:30
pierotofy
Mi sembra un ottimo esercizio!

Gli sbrottamenti che hai incontrato probabilmente vengono dal fatto che un'imlementazione completa per il formato CSV non è proprio così semplice (non si tratta di semplicemente tokenizzare sulla virgola), ci sono regole un pò più complesse: tools.ietf.org/html/…

La cosa bella è che molti programmi esportano su CSV ma non seguono perfettamente lo standard RFC4180, il che crea una serie di nuovi problemi.

Ma siccome l'intento è di generare un simil-csv, fintanto che sei a conoscenza delle limitazioni... tutto a posto!

Come memorizzo la stringa "ciao, come va?" usando "," come separatore? :)
Il mio blog: piero.dev
07/01/15 20:58
Pfffff!!! Meno male che non hai trovato errori, ho sempre il timore che mi sfugga qualcosa (provo e riprovo con mille test, ma il timore rimane lì;). Allora userò queste funzioni nei miei giochetti, d'ora in avanti.

Circa la stringa "ciao, come va?" con la virgola come separatore è al di là dello scopo di queste funzioni. Diciamo che sarebbe sufficiente usare come separatore un carattere poco comune nella lingua italiana? Tipo, che so, '#' o '|' o '\t'...

Per un'implementazione più completa del formato csv ho revisionato ieri l'altro una classe c++ che avevo sviluppato un paio d'anni fa. In quella classe si tiene conto anche di cose come l'uso delle virgolette (che possono essere o non essere presenti) e l'espunzione dei caratteri di spaziatura in apertura e chiusura degli elementi, nonché del fatto che csv "ragiona" secondo uno schema che a me ricorda una matrice bidimensionale (tot campi per ogni record, con i campi divisi da un delimitatore arbitrario e un record per riga). Ricordo che avevo usato come riferimento questa pagina: creativyst.com/Doc/Articles/CSV/…, dove si dice che non esiste un vero standard univoco "ufficiale" per il formato csv (vero o falso?). In effetti la versione che mi hai suggerito (e che ho scaricato) pare che abbia delle piccole differenze rispetto a quella alla quale ho fatto riferimento. Anzi, pare che descriva più versioni, non una sola.

Ammetto che mi piacerebbe condividere la mia classe, ma non mi azzardo a farlo di mia iniziativa perché il file di implementazione è scandalosamente lungo (442 righe! :om: ) e magari anche un po' "spaghettoso". Più maneggevole, invece, il file di intestazione:

/** v1.4.0 - 2015 01 05 **/

#ifndef CSV_H_INCLUDED
#define CSV_H_INCLUDED

#include <stdio.h>


class CSV {

    public:

    CSV();
    CSV( const char *dati, char separatore = ',' );   // throw const char *
    CSV( FILE *dati, char separatore = ',' );   // throw const char *
    CSV( const CSV &ex );                       // throw const char *
    ~CSV();

    CSV operator=( CSV &ex );                   // throw const char *

    void set_csv( const char *dati, char separatore = ',' );   // throw const char *
    void set_csv( FILE *dati, char separatore = ',' );   // throw const char *

    int get_nColonne( void ) { return nColonne; }
    int get_nRighe( void ) { return nRighe; }
    double get_dato_num( int riga, int colonna );
    const char *get_dato( int riga, int colonna );
    int get_dimDato( int riga, int colonna );

    private:

    char *s;
    char **p;
    int nColonne;
    int nRighe;
    size_t dimDati;

    void InizializzaNullo( void );
    void AnalizzaDati( char separatore );
    void IndicizzaDati( char separatore );
    void PulisciStringheDati( void );
    void Copia( const CSV *csvOrig );
    void Dealloca( void );
};

#endif // CSV_H_INCLUDED


Che dici, può valere la pena "svelare" l'implementazione? Potrebbe interessare a qualcuno? Lo farei volentieri per spirito solidaristico, perché quando trovo codice altrui che mi aiuti a capire qualche particolarità sulla quale ho dei dubbi faccio i salti di gioia. Però non sono sicuro d'aver fatto chissà quale capolavoro (non ho modo di confrontarmi con nessuno nel "mondo reale", ed è una grande limitazione) e una "supervisione" sarebbe davvero un toccasana (tra l'altro, servirebbe anche a me per imparare qualcosa).

Scusa se sono un po' logorroico, ma ho sempre tante cose da dire. E poi è un segno d'entusiasmo, no?
07/01/15 21:10
pierotofy
dove si dice che non esiste un vero standard univoco "ufficiale" per il formato csv (vero o falso?)


Falso, RFC4180 è lo standard di riferimento, poi che alcuni programmatori deviano dallo standard per creare diverse implementazioni è un altro discorso.

Potresti fare richiesta per entrare come membro, dopodichè potresti condividere il programma nella sezione C++. pierotofy.it/pages/members/join_module/

Saresti accettato subito :)
Il mio blog: piero.dev
07/01/15 21:28
Postato originariamente da pierotofy:Potresti fare richiesta per entrare come membro, dopodichè potresti condividere il programma nella sezione C++. pierotofy.it/pages/members/join_module/

Saresti accettato subito :)


Guarda che come "programmatore" sono un caprone (vedi la mia firma, qui sotto)!
Comunque vado a vedere quella pagina. Subito!
08/01/15 16:47
pierotofy
Accettato, fammi sapere se ti è arrivata la mail di conferma.
Il mio blog: piero.dev
08/01/15 18:42
AldoBaldo
Ricevuta!

Ma... hai visto il programma? Non è un po' troppo... ehm... "involuto"? C'è da dire che non l'ho in alcun modo riordinato per "presentarlo" -- una volta funzionante l'ho tenuto così com'era dal 2013, e così com'era l'ho spedito. Va be', l'importante è che ora sono un MEMBER! E vai così! Ora dovrò studiare un po' meglio le opportunità offerte da pierotofy.it. Un bello stimolo. Grazie.
Ultima modifica effettuata da AldoBaldo 08/01/15 18:43
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.