Tcl/Tk: Introspecção com comando info

introspecção:
[Do ingl. introspection.] S. f.
1. Observação da vida interior pelo próprio sujeito; exame que alguém faz dos próprios pensamentos e sentimentos.
Dicionário Aurélio – Século XXI

Às vezes, ajuda muito poder examinar TUDO que está acontecendo em um programa/script em um determinado momento. Não só em procedimentos de depuração, embora eu ache que estes sejam os casos mais comuns.

O comando da introspecção em Tcl/Tk é [info]. Sozinho, ele não faz nada. Precisa de pelo menos um argumento. Existem mais de 20 possíveis, mas os mais comuns são:

  • [info vars]: retorna os nomes de todas as variáveis já criadas no programa até o momento em que [info vars] for executado. Se [info vars] estiver no fim do programa, vai revelar todas as variáveis. Se [info vars] estiver no meio programa, não revela as variáveis que forem criadas depois dele.
  • [info exists “nome de variável”]: teste booleano que verifica se uma determinada variável existe, se já foi criada/declarada. É mais fácil fazer assim do que usar [info vars] e ficar procurando uma determinada variável na lista retornada.
  • [info globals]: retorna os nomes de todas as variáveis globais.
  • [info locals]: retorna os nomes de todas as variáveis locais, ou seja, que só existem no contexto de um procedimento (proc). Logo só faz sentido usar [info locals] dentro de um proc.
  • [info procs]: retorna os nomes de todos os procs já criados no programa até o momento em que [info procs] for executado.
  • [info body]: retorna todo o “corpo”, o código de um proc. É como uma radiografia do código fonte. Mostra tudo.
  • [info commands]: retorna os nomes de todos os comandos existentes no programa, inclusive os procs. Também inclui os “apelidos“. Isso inclui TODOS os comandos da linguagem Tcl/Tk, mas observe que alguns comandos podem ter sido apagados.

É sempre mais interessante testar estes comandos no console Tkcon, mas é claro que eles podem ser testados em qualquer programa ou script em Tcl/Tk.

Não é muito interessante testar introspecção em scripts muito pequenos. Quanto maior for o programa, maior será a quantidade de informação a ser garimpada.

Posted in Tcl-Tk | Tagged , , | 2 Comments

C, C++: Dupla negação para conversão em booleano

Em C não existe um tipo nativo booleano, temos 0 como falso e tudo diferente de 0 é verdadeiro. Em C++ existe o tipo booleano, onde verdadeiro e falso correspondem respectivamente a 0 e 1.

Uma forma de fazer um “cast” em C para um tipo booleano compatível com C++ seria usando a dupla negação, como no exemplo a seguir.

int value1 = 0;
int value2 = 1;
int value3 = 50;
int value4 = -1;

printf("value1 = %d\n", !!value1); // Imprime value1 = 0
printf("value2 = %d\n", !!value2); // Imprime value2 = 1
printf("value3 = %d\n", !!value3); // Imprime value3 = 1
printf("value4 = %d\n", !!value4); // Imprime value4 = 1
Posted in C, CPP | Tagged , , , , , , | 5 Comments

Python: Teste condicional e estruturas de dados vazias

Classes que implementam o método __len__, quando testadas com if, este método é invocado. Portanto, para uma lista vazia, o teste falha.

x = [];

if x:
    print "OK" # Nao imprime nada

Para mudar este comportamento, basta reimplementar o método __nonzero__.

class MyList(list):
    def __nonzero__(self):
        return True

x = MyList();

if x:
    print "OK" # Imprime OK
Posted in Python | Tagged , , , , | 2 Comments

Tcl/Tk: Como copiar e colar (clipboard, área de transferência)

Podemos obter o conteúdo (texto) da área de transferência, mais conhecida por aí como “clipboard”, a mesma que é usada nas operações de copiar-e-colar do ambiente gráfico.

Antes, é preciso carregar o pacote Tk. Você pode rodar estes testes com o executável “wish”, que já tem Tk, ou apenas executar “tclsh” e carregar o Tk como um pacote qualquer:

% package require Tk

Pronto! Copie algum texto de um programa qualquer. A seguinte função/procedimento mostra o conteúdo da área de transferência:

% proc clipLeitura {} {
       catch { set varclip [ selection get -selection CLIPBOARD ] } Texto
       return $Texto
}

% clipLeitura
Texto copiado

Só é possível copiar texto. Se o conteúdo não for texto, a função retorna erro, por isso eu sempre uso o comando [catch] na primeira linha. Assim, o procedimento retorna uma string vazia, mas não faz o programa/script/comando morrer.

Não podemos só ler, também podemos escrever:

% proc clipEscrita { Texto } {
       clipboard clear -displayof .
       clipboard append -displayof . $Texto
}

% clipEscrita "Um texto qualquer"

Este comando coloca “Um texto qualquer” na área de transferência. Essa string estará pronta para ser “colada” em qualquer campo ou janela de qualquer programa do ambiente gráfico.

Este procedimento funciona bem com um script que crie pelo menos uma janela Tk e esteja devidamente preparado para lidar com interações do usuário. A maneira mais fácil é testar dentro do console Tkcon, uma espécie de console para ambiente gráfico que, em vez de shell, interpreta Tcl/Tk.

Posted in Tcl-Tk | Tagged , , , , , | Leave a comment

AppleScript: Como copiar e colar (clipboard, área de transferência)

A área de transferência é identificada pelo objeto “the clipboard”. Então basta setar ou obter o seu conteúdo para fazer as operações de copiar e colar.

-- Copiar
set the clipboard to "texto a ser copiado"

-- Colar
(the clipboard)

É recomendado o uso de parênteses ao colar, para evitar confusão com a palavra-chave opcional “the”, utilizada pela linguagem.

Veja um exemplo de uso, com uma janelinha simples que mostra o conteúdo da área de transferência:

-- Mostrar o clipboard atual
display dialog (the clipboard) with title "Área de Transferência"
Posted in AppleScript | Tagged , , , , | 6 Comments

C: Descobrir se um processo está em execução

No Linux é muito comum um daemon, durante sua execução, criar um arquivo .pid dentro de /var/run. Dentro do arquivo syslogd.pid, por exemplo, contém o PID da instância do syslogd em execução. Usa-se este mecanismo para impedir que duas instâncias do mesmo processo rodem simultaneamente e conflitem na obtenção de recursos.

Porém, a simples existência do arquivo .pid não garante que o processo esteja em execução. Ele pode ter sido fechado de uma forma inesperada e não o apagou. Então, temos que ler o conteúdo do arquivo .pid e certificar que o processo com aquele número de PID está em execução.

A forma mais fácil de fazer isso é enviando o sinal 0 para o processo. O sinal 0 é especial e não é de fato enviado, caso contrário o processo destinatário poderia ser fechado se não tratasse o sinal, mas o retorno da função indica se um sinal real seria enviado com sucesso. O código a seguir exemplifica como aplicar a técnica em C:

int main(int argc, char **argv)
{
    unsigned int pid;

    if (argc != 2) {
        printf("Uso: %s PID\n", argv[0]);
        return 1;
    }

    pid = (unsigned int) atoi(argv[1]);

    if (!kill(pid, 0))
        printf("%d esta em execucao.\n", pid);
    else
        printf("%d nao esta em execucao.\n", pid);

    return 0;
}

A mesma técnica pode ser aplicada no terminal:

$ kill -0 123
$ echo $? # Imprime 0 se o PID 123 existir, 1 caso contrario

Note que você precisa ter permissão para enviar um sinal para um determinado processo. Para um usuário sem privilégios especiais, a dica só vai funcionar para verificar a existência de processos iniciados pelo próprio usuário.

Posted in C, Linux, Shell | Tagged , , , , , | 3 Comments

Tcl/Tk: Reproduzir sons

A primeira coisa a se fazer é carregar o pacote Snack:

% package require sound
2.2

Se o número da versão do pacote for retornado, significa que ele está presente e foi carregado. Se não, é preciso verificar a instalação do seu sistema antes de prosseguir.

Em seguida, selecione o arquivo:

% snack::sound s -file "/caminho/do/arquivo.wav"

Daí, é só mandar tocar:

% s play -block 1

Exemplo de função:

proc SomNaCaixa { arquivoDeSom } {
       package require sound
       snack::sound s -file "$arquivoDeSom"
       s play -block 1
}

SomNaCaixa "/caminho/do/arquivo.mp3"

O Snack é multiplataforma e suporta os formatos WAV, AU, AIFF, MP3, CSL, SD, SMP e NIST/Sphere. Também reproduz streaming.

Mais informações:

Posted in Tcl-Tk | Tagged , , , , | Leave a comment

C, C++: Vetores de tamanho zero

Um recurso bastante útil do GCC (apenas) são vetores de tamanho zero. O uso é permitido apenas como último elemento de uma estrutura de dados.

struct pessoa {
    int idade;
    char nome[0];
};
printf("%d\n", sizeof(struct pessoa)); // Imprime "4"

Note que a estrutura tem o mesmo tamanho de um inteiro (na minha máquina). Então podemos concluir que o vetor de tamanho zero não ocupa espaço, ele apenas serve como um identificador para a primeira posição de memória após a estrutura. Isto nos permite fazer algo assim:

struct pessoa * cria_pessoa(int idade, char* nome)
{
    int tamanho = sizeof(struct pessoa) + strlen(nome) + 1;
    struct pessoa *novo = malloc(tamanho);

    novo->idade = idade;
    strcpy(novo->nome, nome);

    return novo;
}
int main(void)
{
    struct pessoa *teste = cria_pessoa(18, "Jose");

    /* Imprime "Jose tem 18 anos." */
    printf("%s tem %d anos.\n", teste->nome, teste->idade);

    free(teste);

    return 0;
}

Note que conseguimos alocar toda a memória para a estrutura em apenas uma operação, o que não seria possível caso “nome” fosse um ponteiro, o que nos custaria mais uma chamada de malloc. Da mesma forma a desalocação de toda a estrutura foi feita usando um comando.

Esta técnica permite maior flexibilidade e um melhor aproveitamento de memória do que construir a estrutura com o atributo nome sendo “char nome[200]” (tamanho fixo) supondo que um nome nunca seria maior que 200 caracteres.

Posted in C, CPP | Tagged , , , , , , | 7 Comments

AppleScript: Obter a pasta do usuário (HOME)

Há um comando bacana para se obter uma referência (alias) à pasta principal do usuário que está rodando o script.

path to home folder
-- Retorna: alias "Macintosh HD:Users:aurelio:"

Se precisar do caminho completo dessa pasta no formato POSIX (com barras), é fácil:

POSIX path of (path to home folder)
-- Retorna: "/Users/aurelio/"

Uma terceira opção é consultar diretamente a variável de ambiente do shell:

do shell script "echo $HOME"
-- Retorna: "/Users/aurelio"
Posted in AppleScript | Tagged , , , , , , | Leave a comment

C: Indo para background com o daemon()

A forma tradicional de um programa ir para background é fazendo um fork(), terminar o processo pai e criar uma nova sessão com setsid(). Outra forma mais simples, que de fato encapsula tudo isso e mais um pouco, é apenas usar a função daemon, como o Ademar sugeriu neste comentário.

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    if (daemon(0, 0)) {
        printf("Erro indo para background.\n");
        return 1;
    }

    printf("Esta mensagem nao deve ser impressa.\n");

    sleep(10); // Durma por dez segundos antes de sair

    return 0;
}

Nada será impresso porque ao passar zero para o segundo parâmetro da função, faz com a saída padrão seja redirecionada para /dev/null, assim como o Cláudio ensinou (e agora vi que dupliquei a dica dele).

Uma vez bem sucedido o comando, nosso processo estará rodando em background desconectado do terminal que o invocou. Você poderá observar que mesmo após o retorno instantâneo do terminal, o nosso programa ainda aparecerá na lista de processos por 10 segundos.

Posted in C | Tagged , , , , , , | 2 Comments