PDA

View Full Version : [C/C++]Costruire lista da file


Marco95
10-03-2013, 17:13
Ciao ragazzi..scrivo perchè ho un problema sul leggere il contenuto di un file e metterlo su una lista concatenata semplice.
Il file di testo è strutturato così:

"luca","pippo","marco","etc...",...
...
...

e il programma apparentemente funzionante che ho scritto è questo:


#include <iostream>
#include <fstream>
#include <string.h>
#include <malloc.h>
using namespace std;
struct nome {
char *p;
nome* succ;
};
typedef nome Tnome;
Tnome* CreaLista();
void Inizializza(char array[],int dim);
void Inserisci(Tnome* &lista,char buffer[]);
void StampaLista(Tnome* lista);
void OrdinaLista(Tnome* &lista);
void Scambia(char* str1[],char* str2[]);

int main()
{
int prova=0;

char buffer[100];
char c;
int contavirgolette = 0;
int k=0;
Tnome *nomipropri;
ifstream testo;
testo.open("prova.txt",ios::in);
nomipropri = CreaLista();
while(!testo.eof())
{
while(contavirgolette<2)
{
c = testo.get();
if (c!='"')
buffer[k++] = c;
else contavirgolette++;
}
buffer[k]=0;
k = 0;
prova++;
contavirgolette = 0;

Inserisci(nomipropri,buffer);
Inizializza(buffer,100);
c = testo.get();


}
testo.close();
StampaLista(nomipropri);



}
Tnome* CreaLista()
{
return NULL;
}
void Inserisci(Tnome* &lista,char buffer[])
{
int i;
Tnome *supporto;

supporto = (Tnome*) calloc(1,sizeof(Tnome));

supporto->succ=lista;
supporto->p = (char*)calloc(strlen(buffer)+1,sizeof(char));

for(i=0;buffer[i]!='\0';i++)
supporto->p[i] = buffer[i];
supporto->p[i] = 0;
lista=supporto;

}
void Inizializza(char array[],int dim)
{
int i;
for(i=0;i<dim;i++)
array[i]=0;
}
void StampaLista(Tnome* lista)
{

while(lista!=NULL)
{
cout << lista->p << endl;
lista = lista->succ;


}
}



Come già detto,il programma funziona,a patto che nel file siano contenuti un numero di nomi limitato...infatti avendo un file contenente circa 5000 nomi,provando a stampare la lista con la funzione stampalista...l'output non è quello che si ci potrebbe aspettare (in particolare l'ultima parola del file non coincide con la prima parola della console..e non riesco proprio a capirne il motivo :confused:
Potreste aiutarmi?
Vi allego anche il file .. 84563
Grazie.

Vincenzo1968
10-03-2013, 20:34
http://img841.imageshack.us/img841/3825/filelista01.jpg

http://img685.imageshack.us/img685/2571/filelista02.jpg

http://www.hwupgrade.org/public/style_emoticons/default/lol.png


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <stdint.h>

typedef struct tagPersona
{
unsigned char *Nome;
struct tagPersona *next;
struct tagPersona *last;
} Persona;

void Print(Persona *first)
{
Persona *n = first;

printf("\n");
while( n != NULL )
{
printf("%s\n", n->Nome);
n = n->next;
}
}

void FreeList(Persona *first)
{
Persona *n1 = first, *n2;
while ( n1 != NULL )
{
n2 = n1->next;
if ( n1->Nome )
free(n1->Nome);
free(n1);
n1 = n2;
}
}

Persona* NewNode(Persona *Pers)
{
Persona *n;
size_t len;

len = strlen(Pers->Nome);

n = (Persona *)malloc(sizeof(Persona));
if( n == NULL )
{
printf("\nNewNode 1: Impossibile allocare la memoria. LOL!!!\n");
return NULL;
}

n->Nome = (unsigned char*)malloc(sizeof(unsigned char) * len + 1);
if ( !n->Nome )
{
printf("\nNewNode 2: Impossibile allocare la memoria. LOL!!!\n");
free(n);
n = NULL;
return NULL;
}

strcpy(n->Nome, Pers->Nome);
n->next = NULL;

return n;
}

Persona* Append(Persona *Pers, Persona *first)
{
Persona *n = first, *nuovo;

if ( first == NULL )
{
nuovo = NewNode(Pers);
if ( !nuovo )
return first;
nuovo->last = nuovo;
return nuovo;
}

nuovo = NewNode(Pers);
if ( !nuovo )
return first;
n = first->last;
n->next = nuovo;
first->last = n->next;

return first;
}

uint64_t MakeBuffer(const char *szFileName, unsigned char **buffer)
{
long x;
uint64_t retSizeData = 0;
long numread;
FILE *fp;

fp = fopen(szFileName, "rb");
if ( fp == NULL )
{
printf("\nLOL!!!\nErrore nell'apertura del file \"%s\". Addio!\n", szFileName);
return 0;
}

#if __linux__ || __APPLE__
fseeko(fp, 0, SEEK_END);
retSizeData = ftello(fp);
fseeko(fp, 0, SEEK_SET);
#else
_fseeki64(fp, 0, SEEK_END);
retSizeData = _ftelli64(fp);
_fseeki64(fp, 0, SEEK_SET);
#endif

*buffer = (unsigned char *)malloc(sizeof(unsigned char) * retSizeData);
if ( !*buffer )
{
printf("\nLOL!!!\nMemoria insufficiente. Addio!\n");
fclose(fp);
return 0;
}

numread = fread(*buffer, 1, retSizeData, fp);
if ( numread < retSizeData )
{
fclose(fp);
free(*buffer);
*buffer = NULL;
printf("\nLOL!!!\nErrore nella lettura del file %s\n", szFileName);
return 0;
}

fclose(fp);

return retSizeData;
}

int DFA(unsigned char *buffer, uint64_t SizeData, Persona **pPers)
{
char c;
long k;
long x;
Persona Pers;

Pers.Nome = (unsigned char*)malloc(sizeof(unsigned char) * 1024);
if ( !(Pers.Nome) )
{
printf("Impossibile allocare la memoria. LOL!!!\n");
return 0;
}

x = 0;
k = 0;
while ( k < SizeData )
{
c = *(buffer + k++);

while ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == ',' )
{
c = *(buffer + k++);
if ( k >= SizeData )
{
free(Pers.Nome);
return k;
}
}

switch( c )
{
case '"':
c = *(buffer + k++);
while ( c != '"' )
{
if ( k >= SizeData )
{
printf("\nErroooooooreeee! File malformato! LOOOOOOOOLLL!!!\n");
free(Pers.Nome);
return 0;
}
Pers.Nome[x++] = c;
if ( x >= 1024 )
{
printf("\nLOOOOOOLLL!!! Ho trovato un nome piu' lungo di 1024 caratteri. LOOOOOOLLL!!! Addio!\n");
free(Pers.Nome);
return 0;
}
c = *(buffer + k++);
}
Pers.Nome[x] = '\0';
x = 0;
*pPers = Append(&Pers, *pPers);
break;
default:
break;
}
}

if ( Pers.Nome )
free(Pers.Nome);

return k;
}

int main(int argc, char* argv[])
{
Persona *pPers = NULL;
unsigned char *buffer = NULL;
uint64_t sizeData = 0;
int ret;

if ( argc != 2 )
{
printf("\nDevi specificare il nome di un file!\n");
printf("\nUso: %s nomefile\n\n", argv[0]);
return -1;
}

sizeData = MakeBuffer(argv[1], &buffer);
if ( !sizeData )
{
printf("\nImpossibile allocare il buffer. Addio!\n");
return -1;
}

ret = DFA(buffer, sizeData, &pPers);

printf("\n");

if ( ret && pPers )
Print(pPers);

printf("\n");

if ( pPers)
FreeList(pPers);

if ( buffer )
free(buffer);

return 0;
}

sottovento
11-03-2013, 07:37
Ciao ragazzi..scrivo perchè ho un problema sul leggere il contenuto di un file e metterlo su una lista concatenata semplice.
Il file di testo è strutturato così:


Come già detto,il programma funziona,a patto che nel file siano contenuti un numero di nomi limitato...infatti avendo un file contenente circa 5000 nomi,provando a stampare la lista con la funzione stampalista...l'output non è quello che si ci potrebbe aspettare (in particolare l'ultima parola del file non coincide con la prima parola della console..e non riesco proprio a capirne il motivo :confused:
Potreste aiutarmi?
Vi allego anche il file .. Grazie.


Ho fatto girare la tua applicazione, ma in effetti riesco ad ottenere TUTTI i nomi che ci sono nel file!!
Anzi, di piu': nel file ci sono 5162 nomi ma quando si va a stampare ne vengono stampati 5163. Infatti c'e' anche il nome vuoto dovuto al newline, del quale non hai tenuto conto nella scrittura dell'applicazione.

Perche' il mio output e' diverso dal tuo? Ci possono essere diversi fattori.
In primis, il tuo programma sembra corretto, ma debole. Per debole intendo che un piccolo problema di qualsiasi genere potrebbe farlo sbagliare, spesso rendendo difficile l'identificazione del problema.
E' molto sensibile all'input e all'ambiente di esecuzione.
Per renderlo piu' robusto, e magari trovare il motivo della differenza di esecuzione:
- quando apri un file NON DARE PER SCONTATO che l'operazione riesca, ma controlla che sia effettivamente riuscita;
- anche l'allocazione della memoria potrebbe non riuscire; pertanto controlla che sia riuscita e stampa un messaggio di errore/termina/fa qualcosa nel caso non riesca;
- il ciclo "leggi virgolette" e' molto dipendente dal file esterno. Un errore nel file ti manda in crash. Ovviamente in caso di errore puoi fare ben poco, ma cerca di evitare eventuali crash.

Vincenzo1968
11-03-2013, 12:47
Improved version con automa a stati:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <stdint.h>

typedef enum tagStates
{
S0,
S1,
S2,
S3
} States;

typedef struct tagPersona
{
unsigned char *Nome;
struct tagPersona *next;
struct tagPersona *last;
} Persona;

void Print(Persona *first)
{
Persona *n = first;

printf("\n");
while( n != NULL )
{
printf("%s\n", n->Nome);
n = n->next;
}
}

void FreeList(Persona *first)
{
Persona *n1 = first, *n2;
while ( n1 != NULL )
{
n2 = n1->next;
if ( n1->Nome )
free(n1->Nome);
free(n1);
n1 = n2;
}
}

Persona* NewNode(Persona *Pers)
{
Persona *n;
size_t len;

len = strlen(Pers->Nome);

n = (Persona *)malloc(sizeof(Persona));
if( n == NULL )
{
printf("\nNewNode 1: Impossibile allocare la memoria. LOL!!!\n");
return NULL;
}

n->Nome = (unsigned char*)malloc(sizeof(unsigned char) * len + 1);
if ( !n->Nome )
{
printf("\nNewNode 2: Impossibile allocare la memoria. LOL!!!\n");
free(n);
n = NULL;
return NULL;
}

strcpy(n->Nome, Pers->Nome);
n->next = NULL;

return n;
}

Persona* Append(Persona *Pers, Persona *first)
{
Persona *n = first, *nuovo;

if ( first == NULL )
{
nuovo = NewNode(Pers);
if ( !nuovo )
return first;
nuovo->last = nuovo;
return nuovo;
}

nuovo = NewNode(Pers);
if ( !nuovo )
return first;
n = first->last;
n->next = nuovo;
first->last = n->next;

return first;
}

uint64_t MakeBuffer(const char *szFileName, unsigned char **buffer)
{
long x;
uint64_t retSizeData = 0;
long numread;
FILE *fp;

fp = fopen(szFileName, "rb");
if ( fp == NULL )
{
printf("\nLOL!!!\nErrore nell'apertura del file \"%s\". Addio!\n", szFileName);
return 0;
}

#if __linux__ || __APPLE__
fseeko(fp, 0, SEEK_END);
retSizeData = ftello(fp);
fseeko(fp, 0, SEEK_SET);
#else
_fseeki64(fp, 0, SEEK_END);
retSizeData = _ftelli64(fp);
_fseeki64(fp, 0, SEEK_SET);
#endif

*buffer = (unsigned char *)malloc(sizeof(unsigned char) * retSizeData);
if ( !*buffer )
{
printf("\nLOL!!!\nMemoria insufficiente. Addio!\n");
fclose(fp);
return 0;
}

numread = fread(*buffer, 1, retSizeData, fp);
if ( numread < retSizeData )
{
fclose(fp);
free(*buffer);
*buffer = NULL;
printf("\nLOL!!!\nErrore nella lettura del file %s\n", szFileName);
return 0;
}

fclose(fp);

return retSizeData;
}

int DFA(unsigned char *buffer, uint64_t SizeData, Persona **pPers)
{
States state = S0;
char c;
long k;
long x;
Persona Pers;

Pers.Nome = (unsigned char*)malloc(sizeof(unsigned char) * 1024);
if ( !(Pers.Nome) )
{
printf("Impossibile allocare la memoria. LOL!!!\n");
return 0;
}

x = 0;
k = 0;
while ( k < SizeData )
{
c = *(buffer + k++);

while ( c == ' ' || c == '\t' || c == '\n' || c == '\r' )
{
c = *(buffer + k++);
if ( k >= SizeData )
{
free(Pers.Nome);
return k;
}
}

switch( state )
{
case S0:
x = 0;
if ( c == '"' )
{
state = S1;
}
else
{
printf("\nS0 Errore: %c input malformato. Addio!\n", c);
free(Pers.Nome);
return 0;
}
break;
case S1:
if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= 128 && c <= 154) || (c >= 224 && c <= 237) )
{
Pers.Nome[x++] = c;
if ( x >= 1024 )
{
printf("\nS1 LOOOOOOLLL!!! Ho trovato un nome piu' lungo di 1024 caratteri. LOOOOOOLLL!!! Addio!\n");
free(Pers.Nome);
return 0;
}
}
else
{
k--;
state = S2;
}
break;
case S2:
if ( c == '"' )
{
Pers.Nome[x] = '\0';
x = 0;
*pPers = Append(&Pers, *pPers);
state = S3;
}
else
{
printf("\nS2 Errore: %c input malformato. Addio!\n", c);
free(Pers.Nome);
return 0;
}
break;
case S3:
if ( c == ',' )
{
state = S0;
}
else
{
printf("\nS3 Errore: %c input malformato. Addio!\n", c);
free(Pers.Nome);
return 0;
}
break;
default:
printf("\nLOL! Errore: %c input malformato. Addio!\n", c);
free(Pers.Nome);
return 0;
}
}

if ( Pers.Nome )
free(Pers.Nome);

return k;
}

int main(int argc, char* argv[])
{
Persona *pPers = NULL;
unsigned char *buffer = NULL;
uint64_t sizeData = 0;
int ret;

if ( argc != 2 )
{
printf("\nDevi specificare il nome di un file!\n");
printf("\nUso: %s nomefile\n\n", argv[0]);
return -1;
}

sizeData = MakeBuffer(argv[1], &buffer);
if ( !sizeData )
{
printf("\nImpossibile allocare il buffer. Addio!\n");
return -1;
}

ret = DFA(buffer, sizeData, &pPers);

printf("\n");

if ( ret && pPers )
Print(pPers);

printf("\n");

if ( pPers)
FreeList(pPers);

if ( buffer )
free(buffer);

return 0;
}


http://img402.imageshack.us/img402/9043/inputnonbuono.jpg

http://img541.imageshack.us/img541/2733/inputnonbuono2.jpg

http://www.hwupgrade.org/public/style_emoticons/default/lol.png

sottovento
11-03-2013, 13:16
Improved version con automa a stati:

<cut>


toglimi una curiosita': perche' scrivi sempre


c = *(buffer + k++);

?

Non e' piu' bello, a vedersi:

c = buffer[k++];

? Sembra anche piu' leggibile.... :D

Vincenzo1968
11-03-2013, 13:19
Perché è più lolloso http://www.hwupgrade.org/public/style_emoticons/default/lol.png

No scherzo, è che sono rimasto al Dragon Book che, nell'esempio del dfa, usa quella notazione. Ma hai ragione, con le quadre è più chiaro, più leggibile.

Marco95
11-03-2013, 13:22
Ho fatto girare la tua applicazione, ma in effetti riesco ad ottenere TUTTI i nomi che ci sono nel file!!
Anzi, di piu': nel file ci sono 5162 nomi ma quando si va a stampare ne vengono stampati 5163. Infatti c'e' anche il nome vuoto dovuto al newline, del quale non hai tenuto conto nella scrittura dell'applicazione.

Perche' il mio output e' diverso dal tuo? Ci possono essere diversi fattori.
In primis, il tuo programma sembra corretto, ma debole. Per debole intendo che un piccolo problema di qualsiasi genere potrebbe farlo sbagliare, spesso rendendo difficile l'identificazione del problema.
E' molto sensibile all'input e all'ambiente di esecuzione.
Per renderlo piu' robusto, e magari trovare il motivo della differenza di esecuzione:
- quando apri un file NON DARE PER SCONTATO che l'operazione riesca, ma controlla che sia effettivamente riuscita;
- anche l'allocazione della memoria potrebbe non riuscire; pertanto controlla che sia riuscita e stampa un messaggio di errore/termina/fa qualcosa nel caso non riesca;
- il ciclo "leggi virgolette" e' molto dipendente dal file esterno. Un errore nel file ti manda in crash. Ovviamente in caso di errore puoi fare ben poco, ma cerca di evitare eventuali crash.


Tralasciando per un momento quei controlli da te citati ho provato a stampare il numero corrispondente al nome...ed effettivamente mi arriva a 5162...il problema è che anzichè partire da 0 mi parte da 4868 e non riesco a capirne il motivo..è come se la schermata nera avesse un tot massimo di linee visualizzabili :/ (comunque a run-time si vedono i valori che partono da 1..ma poi spariscono)


Improved version con automa a stati:

Ho provato a far girare il tuo programma ma mi restituisce un messaggio d'errore sull'allocazione della memoria..

P.s.Ho cancellato le linee

#if __linux__ || __APPLE__
fseeko(fp, 0, SEEK_END);
retSizeData = ftello(fp);
fseeko(fp, 0, SEEK_SET);
#else
_fseeki64(fp, 0, SEEK_END);
retSizeData = _ftelli64(fp);
_fseeki64(fp, 0, SEEK_SET);
#endif

perchè mi dava errore ed ho scambiato gli unsigned char in char...perchè mi diceva invalid type of conversion

Vincenzo1968
11-03-2013, 13:36
valgrind --leak-check=full --show-reachable=yes --track-origins=yes
--log-file=outValgrind.txt ./listadbg listafileinput.txt


==21205== Memcheck, a memory error detector
==21205== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==21205== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==21205== Command: ./listadbg listafileinput.txt
==21205== Parent PID: 21066
==21205==
==21205==
==21205== HEAP SUMMARY:
==21205== in use at exit: 0 bytes in 0 blocks
==21205== total heap usage: 10,329 allocs, 10,329 frees, 208,078 bytes allocated
==21205==
==21205== All heap blocks were freed -- no leaks are possible
==21205==
==21205== For counts of detected and suppressed errors, rerun with: -v
==21205== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

http://www.hwupgrade.org/public/style_emoticons/default/lol.png

Vincenzo1968
11-03-2013, 13:42
Tralasciando per un momento quei controlli da te citati ho provato a stampare il numero corrispondente al nome...ed effettivamente mi arriva a 5162...il problema è che anzichè partire da 0 mi parte da 4868 e non riesco a capirne il motivo..è come se la schermata nera avesse un tot massimo di linee visualizzabili :/ (comunque a run-time si vedono i valori che partono da 1..ma poi spariscono)


Ho provato a far girare il tuo programma ma mi restituisce un messaggio d'errore sull'allocazione della memoria..

P.s.Ho cancellato le linee

#if __linux__ || __APPLE__
fseeko(fp, 0, SEEK_END);
retSizeData = ftello(fp);
fseeko(fp, 0, SEEK_SET);
#else
_fseeki64(fp, 0, SEEK_END);
retSizeData = _ftelli64(fp);
_fseeki64(fp, 0, SEEK_SET);
#endif

perchè mi dava errore ed ho scambiato gli unsigned char in char...perchè mi diceva invalid type of conversion

Strano, a me funziona:

http://img26.imageshack.us/img26/4209/mylistafile01.jpg

http://img802.imageshack.us/img802/8251/mylistafile02.jpg

Che compilatore usi? Io l'ho compilato con GCC 4.7.2 su Linux e Visual Studio 2012 su Windows.

sottovento
11-03-2013, 13:47
Tralasciando per un momento quei controlli da te citati ho provato a stampare il numero corrispondente al nome...ed effettivamente mi arriva a 5162...il problema è che anzichè partire da 0 mi parte da 4868 e non riesco a capirne il motivo..è come se la schermata nera avesse un tot massimo di linee visualizzabili :/ (comunque a run-time si vedono i valori che partono da 1..ma poi spariscono)

Si, ha un numero massimo di linee visualizzabili!! Scusa, pensavo fosse chiaro.
Per cambiarlo sotto Windows, clicca col bottone destro sul titolo, poi scegli Properties e seleziona il "Layout" tab.
A quel punto puoi selezionare la dimensione che ti serve

Vincenzo1968
11-03-2013, 13:56
http://img254.imageshack.us/img254/526/countlistafile.jpg


void Print(Persona *first)
{
uint32_t count = 1;

Persona *n = first;

printf("\n");
while( n != NULL )
{
printf("%5d -> %s\n", count++, n->Nome);
n = n->next;
}
}



./listafile2 listafileinput.txt > out.txt

http://img259.imageshack.us/img259/1870/count2.jpg

Marco95
11-03-2013, 14:01
Copiando esattamente il tuo codice ottengo i seguenti errori:
-invalid conversion from unsigned char* to const char*
in function uint64...
_fseeki64 was no delclaered in this scope
_ftelli64 was not declared in this scope

Io utilizzo codeblocks su windows versione 10.05...

Poi potrsti spiegarmi che cosa sono _fseeki64 e _ftelli64? :confused:

Si, ha un numero massimo di linee visualizzabili!! Scusa, pensavo fosse chiaro.
Per cambiarlo sotto Windows, clicca col bottone destro sul titolo, poi scegli Properties e seleziona il "Layout" tab.
A quel punto puoi selezionare la dimensione che ti serve

Ok provo..
EDIT:Il problema sembrava risiedere proprio là...che INGENUITà

Vincenzo1968
11-03-2013, 14:06
Copiando esattamente il tuo codice ottengo i seguenti errori:
-invalid conversion from unsigned char* to const char*
in function uint64...
_fseeki64 was no delclaered in this scope
_ftelli64 was not declared in this scope

Io utilizzo codeblocks su windows versione 10.05...

Poi potrsti spiegarmi che cosa sono _fseeki64 e _ftelli64? :confused:



http://msdn.microsoft.com/en-us/library/75yw9bf3%28v=vs.80%29.aspx

http://msdn.microsoft.com/en-US/library/0ys3hc0b%28v=vs.80%29.aspx

Eppure è C standard. Non è che con CodeBlocks usi qualche compilatore stravagante tipo DEV-C++?

Non è meglio usare Geany con GCC per Windows?

http://www.geany.org/Support/RunningOnWindows

http://code.google.com/p/mingw-builds/

Marco95
11-03-2013, 14:11
Come compilatore uso Mingw...non so se può essere considerato stravagante :/

Non è meglio usare Geany con GCC per Windows?

http://www.geany.org/Support/RunningOnWindows

http://code.google.com/p/mingw-builds/

Non lo so,mi sono sempre trovato bene con codeblocks...comunque proverò a seguire il tuo consiglio

Vincenzo1968
11-03-2013, 14:20
Al limite c'è anche la versione gratuita di Visual Studio 2012:

http://www.microsoft.com/visualstudio/ita/products/visual-studio-express-products

http://www.microsoft.com/visualstudio/ita/products/visual-studio-express-for-windows-desktop

http://www.microsoft.com/visualstudio/ita/downloads#d-express-windows-desktop

Marco95
11-03-2013, 14:36
Al limite c'è anche la versione gratuita di Visual Studio 2012:


Ok grazie

Vincenzo1968
11-03-2013, 14:46
http://img46.imageshack.us/img46/1350/listafile01win.jpg

http://img40.imageshack.us/img40/231/listafile02win.jpg

http://img9.imageshack.us/img9/273/listafile03win.jpg

Vincenzo1968
11-03-2013, 22:39
http://img542.imageshack.us/img542/6197/fileinputcb.jpg

http://img577.imageshack.us/img577/1881/fileinputcb2.jpg