Newsgroup: it.comp.os.linux.development
Titolo: consigli - ottimizzazione codice

Salve a tutti.ho creato un programmino semplice per esercitarmi che vuole
essere una "simil-reimplementazione" del comando "tail" di *nix, ovvero per
la stampa a video delle ultime tot linee di un file di testo.
Il programma funziona bene ma desidererei che me lo giudicaste/correggeste
voi.
Usage es. :   tail2 20 lang-c.txt
-> stampa a video le ultime 20 linee di lang-c.txt
Scrivo a voi perchè vorrei avere consigli su come implementare/ottimizzare
il codice anche e soprattutto a livello di "modalità di scrittura del
codice", ovvero: utilizzo delle variabili, cicli superflui etc etc..
Spero in qualche vostro commento costruttivo, grazie.
<-----[CODE]----->
#include <stdio.h>
#include <stdlib.h>
void usage();
int num_lines(int);
int offset_count(int line);
void tail_print(char *);
FILE *fd; /* dichiarata esterna per poter */
          /* essere passato alla funzione */
int offset=0;
int main(int argc, char **argv)
{
 int i=0,ltail;
 int lines=0;
 char *buff=malloc(80);
 if(argc!=3)
  usage();
 if((fd=fopen(argv[2],"rb"))== NULL)
 {
  perror("fopen");
  exit(1);
 }
 ltail=atoi(argv[1]);
 lines=num_lines(lines);
 if(ltail == lines)
 {
  fprintf(stderr,"\nYou had choose %d lines of %d...\n",ltail,lines);
  fprintf(stderr,"Don't you ever thought to use \"cat\"? ;-P\n\n");
  exit(1);
 }
 else if(ltail > lines)
 {
  fprintf(stderr,"\n%s error: Lines requested are more then file
lines!\n",argv[0]);
    fprintf(stderr,"You had choose %d lines of %d! Try
again.\n\n",ltail,lines);
  exit(1);
 }
 else
 ;
 offset=offset_count(lines - ltail);
 fseek(fd,offset+1,SEEK_SET);
 tail_print(buff);
 return 0;
}
void usage()
{
 /* Some jokes to test ncurses..if you want.. ;-P
 To use them, remember to decomment ncurses.h
 initscr();
 flash();
 beep();
 refresh();
 endwin();
                                */
 printf("\nTail2\n");
   printf("An implementation of the *nix tail program\n");
 printf("\nUsage: tail2 <num. of line> <filename>\n\n");
 exit(1);
}
int num_lines(int lines)
{
 /* conta il numero di linee del file..
    tipo "wc -l filename"      */
 int i;
 while(1)
        {
                i=fgetc(fd);
                if(i=='\n')
                        lines++;
                if(feof(fd))
                        break;
        }
 rewind(fd);
 return lines;
}
int offset_count(int line)
{
 /* conta il numero di lettere(bytes) da inizio
    al punto in cui devo iniziare a stampare */
 int i=0;
 int bytes=0;
 while(1)
 {
  ++bytes;
  if(fgetc(fd)=='\n')
   ++i;
  if(i==line)
   break;
  if( feof(fd))
   break;
 }
 return bytes-1;
}
void tail_print(char *buff)
{
 /* printa le tot ultime linee del file */
 while(1)
 {
  fgets(buff,79,fd);
  if(feof(fd))
   break;
  fprintf(stderr,"%s",buff);
 }
}
<------[END/CODE]------>


Secondo me se ti diamo delle dritte ti perdi tutto il divertimento :-P
Sei sicuro di volerlo?
--
Alessandro Staltari
staltari(a)
geocities.com

 Sei sicuro di volerlo?
se no non avrei postato.... :)
Sono consigli/trucchetti o altro che possono farmi migliorare la stesura di
codice..
Thanks


Ok, te la sei cercata!
Ho gia' fatto un elenco di osservazioni ieri sera ma il file e' rimasto
a casa. Ovviamente sono solo critiche, non soluzioni ;-)
Te lo mandero' stasera.
Intanto ti annuncio che dovrebbe essere possibile evitare di scorrere il file
per intero due volte, almeno nel caso le righe da visualizzare siano molto
minori del totale. Pensaci.
Alessandro.
P.S. Hai guardato i sorgenti del tail standard?

 P.S. Hai guardato i sorgenti del tail standard?
non li ho trovati.. :( l'ho implementato da nuovo pensando a come avrei
potuto fare..
Con un mini benchmark ( clock() ) ho ottenuto quasi gli stessi  tempi del
tail originale su un campione di 400 linee.
Aspetto le tue critiche. Grazie ancora.
Andrea

tail originale su un campione di 400 linee.
Puoi usare anche time (il comando, non la funzione).
Prova anche con 400000 :-)
Alessandro

 fseek(fd,offset+1,SEEK_SET);
Dopo offset_count() sei gia' al posto giusto, fseek() e' inutile
(anche se non troppo dannoso).
Curioso il fatto che alla fine di affset_count sottrai 1 alla
posizione corrente per poi aggiungerlo nella fseek() (anche qui
non troppo dannoso, ma buffo).
Inoltre scorri sempre il file dall'inizio alla fine per due volte.
Con un trucchetto potresti evitarlo almeno nei casi in cui il numero
di righe da stampare e molto minore del totale del file.
Ciao
--
Alessandro Staltari
staltari(a)
geocities.com

 di righe da stampare e molto minore del totale del file.
su questo io non ti ho ancora capito...
non mi viene in mente come potresti fare se non hai le linee totali che
compongono il file...
illuminami.. :-P
Andy


La prima passata e' obbligatoria, altrimenti, giustamente non sai quante
righe ci sono, ma per la strada potresti lasciare qualche briciolina ogni
tanto...
Se devi mostrare le ultime n righe invece che ricontarle dall'inizio,
potresti ripartire dalla penultima riga multipla di n.
Ciao.
--
Alessandro Staltari
staltari(a)
geocities.com

 briciolina ogni tanto...
Non ho letto tutto il thread, quindi mi scuso se ripeto qualcosa di già
detto.
Un'implementazione ragionevole di tail non deve contare tutte le righe del
file per poter estrarre le ultime. (Si provi a confrontare i tempi di
esecuzione di wc e quelli di tail.) Non ho visto i sorgenti (che comunque
si trovano facilmente sul sito della GNU), ma immagino che tail estragga
le righe leggendo blocchi di dati partendo dalla fine e spostandosi con
lseek (o fseek). Questo è facile da implementare. Ovviamente, è un
approccio possibile con i file, ma non con i dati provenienti da una pipe,
quindi mi aspetto che tail impieghi strategie differenti a seconda della
natura della sorgente dei dati.
Max


Mah, per la verita' il sorgente iniziale prevedeva solo i files quindi il
problema probabilmente non sussiste.
Alessandro Staltari
stal...@geocities.com

 potresti ripartire dalla penultima riga multipla di n.
In realtà è possibile fare di meglio, ovvero leggere il file una volta
sola (altrimenti il programma non potrà funzionare sullo standard
input).
Si fa una cosa del genere: si alloca un vettore di puntatori a stringhe,
lungo quante sono le ultime linee richieste; poi lo si usa come buffer
circolare, ovvero si leggono tutte le righe del file e si mettono in
questo vettore. Arrivati alla fine, nel vettore ci saranno proprio le
righe volute.
Servirà un indice per tenere conto di qual è la riga più vecchia nel
vettore.
-- 
Saluti,
    Mardy
http://castellina.org/interlingua

Si fa una cosa del genere: si alloca un vettore di puntatori a stringhe,
[snip]
Si, ma se le righe da visualizzare fossero tante e la memoria poca, potrebbe
non funzionare.
Alessandro.

 non li ho trovati..
Non so se e' quello "standard", ma e' quello che viene usato da Linux (credo
:-).
http://www.gnu.org/software/textutils/textutils.html
Ciao
Alessandro.

 input).
Tanto per essere pignoli: non è importante il fatto che si tratti o meno
dello standard input. Mi spiego.
Come dicevo nell'altro mio messaggio, tail utilizza due strategie diverse
per i file e per le pipe.  Con le pipe non è possibile usare lseek() e
spostarsi in fondo.
Però non è detto che non si possa mai usare lseek() sullo standard input.
Ad esempio, con il questo comando
    tail < file
tail usa lseek() sul file descriptor 0.
Max


Quindi i comandi
tail < file
cat file | tail
si comportano diversamente? In effetti sono diverse...
--
Alessandro Staltari
staltari(a)
geocities.com

 si comportano diversamente? In effetti sono diverse...
Senz'altro. Nel secondo caso cat legge il file e lo scrive nel suo stdout.
Nel primo la shell apre il file, usa dup2() per rendere il descriptor 0
una copia del descriptor restituito dalla open(), ed esegue tail con
execve().
Max

 non funzionare.
Ehm... Linux ha un sistema di memoria virtuale. Se non c'e' RAM
usa il disco. Mettendo a disposizione sufficiente disco....
In ogni caso un monitor in modalita' testo non contiene piu' di
40 righe (se non ricordo male e non tutte le schede supportano
modalita' strane).
Un terminale X-Windows non so quante righe riesce a memorizzare
ma non credo piu' di qualche centinaio.
Fare il tail di piu' di qualche decina/centinaio di rige forse
non ha molto senso, a mio avviso, il problema che ti poni e'
eccessivo.
C:\>iao Angelo.
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG


Il tail puo' essere fatto non solo per visualizzare a video ma,
ad esempio, selezionare l'ultimo milone di righe di un file di
log immenso.
Alessandro.

 circolare).
Se ci sono poche righe da selezionare queste comunque stanno in meoria,
se c'e' una marea di linee da selezionare si aspetta. Non e' che un
sistema sia l'optimum per qualsiasi problema.
C:\>iao Angelo



Non vedo vantaggi concreti nell'uso del buffer circolare: se le righe sono
poche fare un fseek non dovrebbe essere un grosso problema per il FS che
bufferizzando i dati recenti farebbe semplicemente il suo mestiere senza che
noi ci mettiamo a scimmiottarlo duplicando le sue funzioni, e se fossero tante
rischierebbe di non funzionare.
Secondo me il presunto aumento di prestazioni non giustifica una riduzione di
funzionalita'.
Alessandro.

 wrote in message
news:k6nI8.107791$
g04....@tornado.fastwebnet.it
Ti va di passare in privato? Non credo che questa discussione
interessi qualcun'altro a parte noi due.
C:\>iao Angelo.
P.S. Il mio indirizzo e' valido.



Come ritieni opportuno.
A me non mi sembra di essere cosi' fuori dal topic, forse all'autore del post
iniziale potrebbe interessare.
Comunque nel caso gli interessi potra' contattarci.
-- 
Alessandro Staltari
staltari(a)
geocities.com

 poche fare un fseek non dovrebbe essere un grosso problema per il FS che
Un vantaggio è implicito in quello che hai scritto tu: se non puoi fare
fseek...



Si, certo. Io mi riferivo al caso di file "standard" su disco :-)
Alessandro.

 Spero in qualche vostro commento costruttivo, grazie.
Se non ricordo male, sul K&R c'era un implementazione di tail, prova
ad andartela a vedere, se hai il libro, ma penso di si, visto che 
ti preoccupi della buona stesura di codice in C.
ciao ciao