:TITLE: Mais construção de comandos - format, list
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl33.lsn,v 1.6 2000/04/24 16:17:52 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# Veja o arquivo "AVISO" com os termos da licença.
;#
;#*********************************************************
;# Portuguese translation: Lucio Agostinho Rocha
;# E-mail: outrosdiasvirao@yahoo.com.br
;# Last update: 16/01/2006
;#*********************************************************
:LESSON_TEXT_START_LEVEL 0:
O ponto principal para tomar cuidado na construção de comandos
de strings para <B>eval</B> é como os argumentos serão agrupados
quando o comando for avaliado.
<P>
Por exemplo: <PRE><CODE>
eval puts OK
</PRE></CODE>
exibiria a string OK. Todavia,<PRE><CODE>
eval puts Não OK
</PRE></CODE>
irá gerar um erro.
<P>
A razão do segundo comando gerar um erro é que o comando
<B>eval</B> utiliza o comando <B>concat</B> para juntar seus
argumento em um comando de string. Isso faz com que as duas
palavras <B>Não</B> e <B>OK</B> sejam tratadas como dois
argumentos para <B>puts</B>. Se houver mais de um argumento
para <B>puts</B>, o primeiro argumento deve ser um ponteiro
para arquivo.
<P>
Formas corretas de escrever o segundo comando incluem estas:
<PRE><CODE>
eval [list puts {Não OK}]
eval [list puts "Não OK"]
set cmd "puts" ; lappend cmd {Not OK}; eval $cmd
</CODE>
</PRE>
Tão logo você mantenha indicações de como os argumentos que você apresenta
ao comando <B>eval</B> serão agrupados, você pode usar muitos métodos de
criação de string para <B>eval</B>, incluindo os comandos de string e
o comando <CODE>format</CODE>.
<P> 
Um comando que não esteja completo pode ser checado com <B>info complete</B>.  
<B>Info complete</B> pode também ser usado em um programa interativo para
determinar se a linha sendo digitada é um comando completo, ou o usuário
apenas entrou uma nova linha para formatar o comando melhor.
<DL>
<B><DT>info complete</B> <I>string</I>
<DD>Se <I>string</I> tem pares de chaves, colchetes ou parênteses
então o valor 1 é retornado; caso contrário, 0 é retornado.
</DL>
:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
Podem ocorrer muitos resultados inesperados quando você tentar compor comandos
de string com <B>eval</B>.
<P>
Por exemplo: <PRE><CODE>
eval puts OK
</PRE></CODE>
exibiria a string OK. Todavia,<PRE><CODE>
eval puts Não OK
</PRE></CODE>
irá gerar um erro.
<P>
A razão do segundo comando gerar um erro é que o comando
<B>eval</B> utiliza o comando <B>concat</B> para juntar seus
argumentos em um comando de string. Isso faz com que as duas
palavras <B>Não</B> e <B>OK</B> sejam tratadas como dois
argumentos para <B>puts</B>. Se houver mais de um argumento
para <B>puts</B>, o primeiro argumento deve ser um ponteiro
para arquivo.
<P>
Formas corretas de escrever o segundo comando incluem estas:
<PRE><CODE>
eval [list puts {Não OK}]
eval [list puts "Não OK"]
set cmd "puts" ; lappend cmd {Não OK}; eval $cmd
</PRE></CODE>
Tão logo você mantenha indicações de como os argumentos que você apresenta
ao comando <B>eval</B> serão agrupados, você pode usar muitos métodos de
criação de string para <B>eval</B>, incluindo os comandos de string e
o comando <CODE>format</CODE>.
<P>
Os métodos recomendados de construção de comandos para <B>eval</B> são os
que usam os comandos <B>list</B> e <B>lappend</B>. Esses comandos tornam-se
difíceis de usar, todavia, se você precisar colocar chaves em um comando,
como foi feito na lição anterior.
<P>
O exemplo da lição anterior é reimplementado no exemplo de código utilizando
lappend.
<P> 
Um comando que não esteja completo pode ser checado com <B>info complete</B>.  
<B>Info complete</B> pode também ser usado em um programa interativo para
determinar se a linha sendo digitada é um comando completo, ou o usuário
apenas entrou uma nova linha para formatar o comando melhor.
<DL>
<B><DT>info complete</B> <I>string</I>
<DD>Se <I>string</I> tem pares de chaves, colchetes ou parênteses
então o valor 1 é retornado; caso contrário, 0 é retornado.
</DL>
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
O comando <B>eval</B> é muito poderoso, mas você precisa manter indicações
de qual string exatamente está sendo avaliada quando você usa este comando.
<P>
Por exemplo: <PRE><CODE>
eval puts OK
</PRE></CODE>
exibiria a string OK. Todavia,<PRE><CODE>
eval puts Não OK
</PRE></CODE>
irá gerar um erro.
<P>
A razão do segundo comando gerar um erro é que o comando
<B>eval</B> utiliza o comando <B>concat</B> para juntar seus
argumento em um comando de string. Isso faz com que as duas
palavras <B>Não</B> e <B>OK</B> sejam tratadas como dois
argumentos para <B>puts</B>. Se houver mais de um argumento
para <B>puts</B>, o primeiro argumento deve ser um ponteiro
para arquivo.
<P>
Formas corretas de escrever o segundo comando incluem estas:
<PRE><CODE>
eval [list puts {Não OK}]
eval [list puts "Não OK"]
set cmd "puts" ; lappend cmd {Não OK}; eval $cmd
</PRE></CODE>
Você pode encontrar problemas com esta característica quando
você estiver usando o conteúdo de variáveis para construir o comando de
string. Por exemplo:
<PRE><CODE>
set x OK
eval puts $x

set x NÃO OK
eval puts $x </CODE>
</PRE>
Novamente, na primeira vez que <B>eval</B> é chamado, ele irá exibir
<B>OK</B>, e na segunda vez ele irá gerar um erro. Neste caso, isso é
porque o $x é substituído com <B>NÃO OK</B> na fase de substituição Tcl.
<P>
Novamente, este código irá funcionar:
<PRE><CODE> 
set x "NÃO OK" 
eval [list puts $x] 
</CODE>
</PRE>
Tão logo você mantenha indicações de como os argumentos que você apresenta
ao comando <B>eval</B> serão agrupados, você pode usar muitos métodos de
criação de string para <B>eval</B>, incluindo os comandos de string e
o comando <CODE>format</CODE>.
<P>
Os métodos recomendados de construção de comandos para <B>eval</B> são os
que usam os comandos <B>list</B> e <B>lappend</B>. Esses comandos tornam-se
difíceis de usar, todavia, se você precisar colocar chaves em um comando,
como foi feito na lição anterior.
<P>
O exemplo da lição anterior é reimplementado no exemplo de código utilizando
lappend.
<P> 
Um comando que não esteja completo pode ser checado com <B>info complete</B>.  
<B>Info complete</B> pode também ser usado em um programa interativo para
determinar se a linha sendo digitada é um comando completo, ou o usuário
apenas entrou uma nova linha para formatar o comando melhor.
<DL>
<B><DT>info complete</B> <I>string</I>
<DD>Se <I>string</I> tem pares de chaves, colchetes ou parênteses
então o valor 1 é retornado; caso contrário, 0 é retornado.
</DL>
<P>
Como normalmente foi feito, execute o exemplo, e siga o código e a saída.
<P>
O primeiro comando <B>eval</B> mostra um uso trivial do comando
<B>eval</B> que funciona.
<P>
O próximo comando <B>eval</B> utiliza <B>lappend</B> para criar uma
palavra múltipla com puts que também funcionará.
<P>
O próximo comando demonstra como um uso trivial de <B>eval</B> pode falhar.
Novamente, isso falha porque não há nada no comando para agrupar
<B>NÃO OK</B> em um único argumento. Quando <B>eval</B> chama <B>concat</B> 
ele irá tratar as duas palavras como dois argumentos. Tente alguns métodos
para tornar este comando correto.
<P>
O comando <B>format</B> no próximo exemplo cria a string
<CODE> puts "Mesmo isso funciona"</CODE>. Neste exemplo, o segundo
argumento <B>"Mesmo isso funciona"</B> está delimitado por aspas
duplas em um único argumento, ao invés de ser tratado como 
três argumentos.
<P>
O próximo exemplo usa uma variável para demonstrar o mesmo processo.
<P>
O próximo exemplo utiliza lappend para criar o proc nomeArqTemp que
foi usado na lição anterior. Lembre-se que um comando Tcl é realmente
uma lista, e este exemplo se torna um pouco mais óbvio.
<P>
A primeira linha, <CODE>set cmd {proc nomeArqTemp }</CODE> inicializa
o comando de string para apenas conter <B>proc nomeArqTemp</B>.  
<P>
A próxima linha, <CODE>lappend cmd ""</CODE> adiciona um item vazio de
lista a <B>cmd</B>. O item vazio de lista é <CODE>{}</CODE>, que é um
campo de argumento vazio. Neste ponto, <B>cmd</B> contém a string
<B>proc nomeArqTemp {}</B>.
<P>
A próxima linha é o corpo do proc. As coisas para levar em consideração
aqui são as aspas duplas precedidas por barras invertidas e os sinais de
cifrão. Se o corpo do proc fosse demilitado por chaves, então as barras
invertidas não seriam necessárias. Todavia, neste caso, o
<CODE>[pid]</CODE> não deveria ser avaliado, e o <CODE>[pid]</CODE>
seria parte do proc, ao invés de ter o número do pid colocado na
string.
<P>
Depois disso, o corpo do proc é mostrado.
<P>
Depois, o comando <CODE>format</CODE> é usado para criar a definição
do comando proc. A primeira linha apenas inicializa o comando de string,
como antes.
<P>
As linhas subseqüentes adicionam o corpo do proc ao comando. As
últimas linhas usam o comando <B>format</B> para juntar os resultados
de <CODE>[pid]</CODE> na linha de comando.
:TEXT_END:

:CODE_START:
;# Isso funciona
set cmd OK
eval puts $cmd

;# Isso também funciona
set cmd puts; lappend cmd {Também OK}; eval $cmd

;# Isso gera um erro
set cmd "NÃO OK"
eval puts $cmd

eval [format {%s "%s"} puts "Mesmo isso funciona"]

set cmd "E mesmo isso pode ser feito para funcionar"

eval [format {%s "%s"} puts $cmd ]

set numArqTemp 0

;# Criação do proc nomeArqTemp com lappend

set cmd { proc nomeArqTemp }
lappend cmd ""  
lappend cmd "global num; incr num; return \"/tmp/TMP.[pid].\$num\""
eval $cmd

puts "\nEste é o corpo da definição do proc:"
puts "[info body nomeArqTemp]\n"

;# Agora, é mostrado um comando incompleto sendo capturado pelo
;# info complete

set cmd {puts "Isso é legal!}

if {[info complete $cmd]} {
  eval $cmd
  } else {
  puts "COMANDO INCOMPLETO: $cmd"
  }
:TEXT_END:

