Newsgroup: it.comp.lang.perl
Titolo: Automa a stati finiti efficiente in Perl. Come?

Ciao a tutti.
Ancora chiedo come poter realizzare in modo efficiente in perl quanto
segue:
devo ricevere come server SMTP oltre ai comandi anche il famigerato comando
DATA. Come tutti sapete dopo il comando data si deve acquisire tutto il
messaggio fino ed esclusa la sequenza <CR><LF>.<CR><LF>.
come fare delle letture di lunghezza fissa con sysread() e riconoscere
il passaggio delle sequenza di fine messaggio SENZA MAI acquisire uno
scalare che debba contenere tutto il messaggio?
Ad ogni lettura devo controllare de la parte finale di quanto letto e':
"\r\n.\r" o "\r\n." o "\r\n" o "\r"
se no trasmetto quanto letto al SMTP di relay, se si trasmetto escluso
il trailer da esaminare. alla prossima lettura concateno il traile r della
lettura precedente e cerco la seq intera.
In C con il vantaggio di operare a basso livello con l' e con l' aritmetica
dei puntatori a carattere avevo imprementato un Automa a Stati finiti
deterministico di Knut-Morris-Pratt cosi' come Sedgewich lo descrive e
per far scattare l' automa dovevo solo conservare un singolo char.
La versione C e' molto efficiente, ma come fare una cosa simile in Perl?
Questo problema ce l' ho sempre per codive per networking e ogni volta
lo risolvo in modo non troppo generale per tutti gli scopi, e soprattutto
non sono convinto dell' efficienta, visto che devo usare scalari Perl
e non puntatori a caratteri.
Un approccio C-Lyke e' stato di usare substr() per selezionare i singoli
caratteri e far scattare l' automa, ma e' ovviamente molto inefficiente
visto de devo iterare molte chiamare a substr() e ricevere molti scalari
di un carattere che di solito non servono. Come usare pochi metodi nativi
Perl per questa missione?
Dell' efficienza della sub che segue sono abbastanza soddisfatto:
mi permette di avere un flusso di linee partendo da un flusso di blocchi,
ma devo imporre dei limiti massimi alla lunghessa dello scalare.
per gestire il comando data non va bene. Una soluzione comunque la trovero'
ma volevo una volta per tutte trovare una soluzione efficiente.
# $_[0] $instring
# $_[1] "\r\n"
# Restituisce: ($lineatrovata, $resto) o (undef(), $lineaintera)
sub rawin
{
  my $pos = 0;
  if (($pos = index($_[0], $_[1], $pos)) >= 0)
    {
      return ((substr $_[0], 0, $pos),
              (substr $_[0], $pos + length($_[1])));
    }
  else { return (undef() , $_[0]); }
}
# prima di richiamarla con il prossimo blocco di input si deve
# concatenare il secondo argomento restituito perche potrebbe
# terminare con "\r" e all' inizio dell' input successivo potrebbe
# esserci "\n". Prima di fare altro input si deve chiamare rawin
# fino a che il primo arg restituito sia undef() cioe' il buffer
# non contiene linee terminate.
Ciao
Roberto.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 messaggio fino ed esclusa la sequenza <CR><LF>.<CR><LF>.
Non sforzate oltre le mening!
Ho risolto a modo mio.
#--------------
# $_[0] $instring
# $_[1] "\r\n.\r\n"
# Restituisce: ($lineatrovata, $stato) o ($lineaintera, "")
sub state
{
  my $t0 = $_[0]; my $t1 = $_[1];
  while ((length $t1) > (length $t0)) { chop $t1; }
  while (((substr $t0, -(length $t1)) ne $t1) && ($t1 ne ""))
    { chop $t1; }
  if ($t1 ne "")
   { return ((substr $t0, 0, -(length $t1)), $t1); }
  else { return ($t0, ""); }
}
#----------
Al secondo valore restituito viene concatenato il prossimo input, mentre
il primo, che e' parte del contenuto di DATA, e' disponibile per forward,
elaborazioni e archiviazioni. Quindi riesco a mantenere lo scalare in
una dimensione MAX di $MAXINPUT = 8192 + 4 che e' "\r\n.\r" senza "\n"
finale.
Non so' se e' la piu' efficiente possibile, ma funzia e senza regex
quindi non dovrebbe essere male. Attenzione che non e' ancora ben
debuggata.
Ciao.
