Biblioteca

13. Re: Biblioteca

Paulo
paulo1205

(usa Ubuntu)

Enviado em 30/09/2012 - 05:48h

Eu não conheço biblioteca de compatibilidade entre DOS e UNIX num nível como os desses comandos externos. Aliás, nem sei se deveria existir, pois, como está explícito, trata-se de comandos externos.

Eu ainda acho que o melhor é não se preocupar com o que não é essencial, mas dado que existe uma realidade que tem suas próprias restrições e regras (no caso dela, ser aluna de um curso que pode ser engessado, com um professor que talvez seja cabeça-dura -- quem sabe?), pode-se já estar fora do "tanto quanto possível" a que me referi na mensagem anterior. Nesse caso, uma primeira possibilidade seria ela mesma criar uma biblioteca com esse fim, e usá-la em todos os seus programas dali para frente. Um esqueleto disso poderia ser algo como vai abaixo.

#include <stdlib.h>

int pausar(void){
#if defined(__unix)
return system("echo -n 'Pressione <ENTER> para prosseguir... ' ; read dummy")==0;
#elif defined(_MSDOS_) || defined(_WIN32) || defined(_WIN64) || defined(_OS2)
return system("pause")==0;
#else
/*
Sistema desconhecido. Como o C padrão é agnóstico sobre o ambiente
de execução, o mais seguro é não fazer coisa alguma.
*/
return 0;
#endif
}

int limpatela(void){
#if defined(__unix)
/*
O comando "clear" é um comando externo, que pode nem mesmo estar
instalado. Se não conseguir executar, a tela vai continuar "suja",
e ainda vai surgir nela uma mensagem de erro.
*/
return system("clear")==0;
#elif defined(_MSDOS_) || defined(_WIN32) || defined(_WIN64) || defined(_OS2)
return system("cls")==0;
#else
/*
Sistema desconhecido. Como o C padrão é agnóstico sobre o hardware,
pode ser que nem exista tela; logo não faz coisa alguma.
*/
return 0;
#endif
}


O uso efetivo dessa minibiblioteca obrigará a troca de todas as ocorrências de system("pause") ou system("cls") no restante do programa pela respectiva função correspondente. Note que as duas funções retornam 1 se tiverem executado corretamente, e 0 em caso de falha.

O exemplo acima continua sendo muito ruim pois, como eu disse anteriormente, system() chama programas externos tanto no UNIX quanto no Windows. O que parece muito simples tem os seguintes etapas (cada uma delas individualmente sujeita a falha e com custos de computação associados): (1) o processo original cria um processo subordinado (filho), e fica parado esperando o filho terminar; (2) o processo filho chama o interpretador de comandos do sistema ("sh -c" no Unix, "command.com" no MS-DOS, e "cmd.exe" no Windows), para que ele interprete e execute o comando descrito na string fornecida como parâmetro; (3) o interpretador de comandos processa a string, que pode se desdobrar em um ou mais comandos; (4) o interpretador executa os comandos identificados no passo 3 (a depender do caso, esses comandos podem invocar outros programas externos, adicionando ainda maior consumo de recursos do sistema); (5) ao final da execução do(s) comando(s), o interpretador de comandos deve computar um valor de resposta a ser enviado ao processo original; (6) o interpretador de comandos notifica ao sistema que quer terminar, enviando ao processo pai o valor calculado; (7) o processo original recebe o código de resposta enviado pelo filho, permitindo ao sistema operacional limpar totalmente os recursos consumidos durante a execução do filho.

Uma evolução posterior dessa biblioteca seria trazer para dentro dela própria aquilo que os comandos externos fazem. Isso teria a vantagem de eliminar os gastos de recursos e tempo de processamento envolvidos com a criação de outro processo e execução de comandos externos. O preço a pagar é ter de escrever um pouco mais de código na implementação da biblioteca. No entanto, depois de implementado na biblioteca, não haverá mais essa necessidade para usar em todos os programas dali para frente.

Um exemplo de como fazer as funções de pausa e de limpeza de tela nativamente no UNIX segue abaixo. Note que o resultado não é código muito extenso em nenhuma das duas funções -- eu diria até que é curto, especialmente se você descontar os comentários explicativos, mas requer o uso de alguns recursos não triviais para iniciantes. Certamente daria para fazer algo semelhante no Windows (e eu até recomendo, como exercício, que você o faça, quando puder), mas eu não conheço essa solução de antemão (até cheguei a dar uma olhada na MSDN sobre funções de console, mas eu não teria como testar porque não estou no Windows agora e, mesmo que estivesse, o único compilador C que tenho instalado nele é o do Cygwin, que emula um ambiente UNIX e meio que esconde o Windows que está por trás).

#if defined(__unix)
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>

#include <curses.h>
#include <term.h>
#endif

#include <stdio.h>
#include <stdlib.h>

int pausar(void){
#if defined(__unix)

static const char msg[]="Pressione <ENTER> para prosseguir... ";
static const char nl='\n';

int cons_fd;
struct termios old_tc, tc;
char ch;

/*
Obtém descritor do terminal controlador do processo, mesmo que as
entradas e saídas padrão tenham sido redirecionadas. Se falhar,
então não tem terminal controlador, logo não faz sentido pausar.
*/
if((cons_fd=open("/dev/tty", O_RDWR, 0x644))==-1)
return 0;

/* Obtém e salva configuração atual do terminal. */
tcgetattr(cons_fd, &old_tc);

/*
Copia configuração obtida, alterando propriedades necessárias para
uma leitura sem eco na tela, para mínimo impacto visual.
*/
tc=old_tc;
tc.c_lflag&=~(ICANON|ECHO);
tc.c_cc[VMIN]=1;
tc.c_cc[VTIME]=0;
tcsetattr(cons_fd, TCSANOW, &tc);

/* Exibe mensagem de prompt. */
write(cons_fd, msg, sizeof(msg)-1);

/* Aguarda o caráter correspondente à tecla desejada. */
while ( read(cons_fd, &ch, 1)==1 && ch!='\n' )
; /* Isso mesmo: nada dentro do corpo do loop. */

/*
Pula linha, para evitar que o próximo texto escrito na tela fique
junto da mensagem de prompt.
*/
write(cons_fd, &nl, 1);

/* Restaura configuração original do terminal e fecha seu descritor. */
tcsetattr(cons_fd, TCSANOW, &old_tc);
close(cons_fd);

/* Retorna indicando sucesso. */
return 1;

#elif defined(_MSDOS_) || defined(_WIN32) || defined(_WIN64) || defined(_OS2)

return system("pause")==0;

#else

/*
Sistema desconhecido. Como o C padrão é agnóstico sobre o ambiente
de execução, o mais seguro é não fazer coisa alguma.
*/
return 0;

#endif
}

int limpatela(void){
#if defined(__unix)

/* Só limpa a tela se a saída padrão estiver ligada a um terminal. */
if(!isatty(STDOUT_FILENO))
return 0;

/*
Vê se o tipo do terminal já está definido, por meio da variável global
cur_term, declarada em term.h.
*/
if(cur_term==NULL){
/* Não está ainda. Tenta defini-lo. */
int err_code;
if(setupterm(NULL, STDOUT_FILENO, &err_code)==ERR || err_code!=1){
/* Falha. Retorna indicando que nada foi feito. */
return 0;
}
}

/*
Envia código de limpeza de tela. O valor retornado será 1 se
tiver tido sucesso, e zero de tiver havido falha.
*/
return putp(clear_screen)==OK;

#elif defined(_MSDOS_) || defined(_WIN32) || defined(_WIN64) || defined(_OS2)

return system("cls")==0;

#else

/*
Sistema desconhecido. Como o C padrão é agnóstico sobre o hardware,
pode ser que nem exista tela; logo não faz coisa alguma.
*/
return 0;

#endif
}


(Note que a função limpatela(), ao fazer uso das funções providas pela biblioteca curses, necessitará da inclusão dessa biblioteca no momento da geração do programa executável.)


  



01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts