Cadastro de Clientes em COBOL – CRUD

Apesar de eu achar que a versão estável do gnu COBOL necessite diversas melhorias que veremos no decorrer do artigo, não impede a sua utilização para aplicações diversas. Resolvi fazer um programinha CRUD (Create, Read, Update, Delete) para cadastrar clientes. A ideia veio depois de ligar para uma empresa que entrega água e eles pedirem o endereço mesmo já tendo comprada deles. É só a empresa ter um cadastro, pedir o telefone, informar ao programa e confirmar o endereço. É um programa simples e foi feito mais para mostrar algumas características da linguagem do que para mostrar boas técnicas de programação.

Abaixo, podemos ver o programa sendo executado, mostrando as opções de inclusão, consulta, alteração e exclusão de registros de clientes.

O fonte do programa encontra-se no github. Para baixar, você pode usar o botão Download zip ou no botão raw e salvar como clientes.cob. Para acompanhar as explicações abaixo, é interessante que você abra o link acima em outra janela ou aba. Não vou colocar o número de linha nas explicações pois existe a possibilidade de alterações e teria que adequar o artigo. Também é interessante pois obriga você a ler o programa até achar a entrada especificada.

FILE-CONTROL

Temos as definições de como será feito o acesso ao arquivo. Podemos ter diversas entradas select, uma para cada arquivo. O arquivo pode estar em disco (nosso caso), fita etc.. Será indexado pela chave fs-key e o status fs-stat nos informará o resultado das operações (chave existe, não existe, erro na abertura, etc.). Podemos incluir chaves alternativas e as mesmas poderão ser duplicadas, o que não acontece com a chave principal.

FILE SECTION

Cada arquivo definido em file-control deverá ter uma entrada FD na file section. Aqui informamos o nome do arquivo (poderia estar no select no lugar de DISK) e a estrutura do registro. Inclui um nível em FS-KEY para deixar mais patente que existe a possibilidade de termos uma chave primária composta. Se não sabemos exatamente como será a estrutura do arquivo, é interessante incluirmos um espaço já que os registros são fixos. Alterações posteriores implicariam em fazer um programa para mover os dados da estrutura antiga para a nova. Apesar de não ser difícil é uma etapa desnecessária. O campo FILLER (poderíamos usar um nome como fs-reserva mas filler é mais comum) serve apenas para reservar espaço caso desejarmos adicionar mais alguma informação ao registro. Neste caso, reservamos um espaço de 20 caracteres que poderão ser utilizados posteriormente definido-se os novos campos. Por exemplo, podemos incluir o campo fs-uf pic x(02) e deixamos e alteramos filler para pic x(18).

NIVEL 88 (WS-OPCAO)

Especifica nomes condicionados ao valor da variável melhorando a legibilidade do programa. No caso de ws-opcao, se o usuários selecionar a opção 1 para incluir, é muito mais legível eu verificar if e-incluir do que if ws-opcao=1. É possível especificar mais de um nome como no caso de e-encerrar onde o usuário pode digitar um X maiúsculo ou minúsculo. Também é possível especificar uma faixa. Poderíamos ter e-numerico value is 0 thru 9.

COPY screenio.

Apenas inclui o código de retorno quando o usuário pressionar teclas especiais como Esc, F1, etc.. Utiliza o nível 78 (semelhante ao 88) para deixar o programa mais legível. Temos, por exemplo, 78 COB-SRC-ESC VALUE 2005. e é utilizado cob-src-esc nas comparações em vez de 2005 que não significa nada.

SCREEN SECTION

Aqui definimos as diversas telas do nosso programa. Podemos utilizar display nome que irá apenas mostrar a tela ou accept tela que irá mostrar e solicitar a entrada dos dados existentes. Vale lembra que enter confirma a entrada. Para mudar de um campo para outro é utilizado a tecla Tab (próximo campo) ou Shif+Tab (campo anterior)

Em ss-cls limpamos a tela e mostramos um cabeçalho informando a opção sendo executada (menu, inclusão, exclusão, etc.) e um rodapé que poderá conter alguma informação adicional na última linha. Utilizamos a variável ws-numl que é definida em tempo de execução.

Em ss-menu temos a definição do menu do programa. O auto utilizado na entrada de ws-opcao permite que não seja necessário pressionar enter. Quando o campo é preenchido o programa segue adiante automaticamente. Quando a entrada possui mais de um caractere, use com cautela para que o usuário não se confunda ou seja induzido a erro. Aqui seria mais interessante usar LINE PLUS 1 em vez de informar diretamente o número da linha. Assim, permitiria um deslocamento do menu para cima ou para baixo com mais facilidade.

Em ss-tela-registro temos a definição da tela de entrada para os dados do cliente. Temos níveis diferentes principalmente pela necessidade da entrada apenas da chave para alteração ou inclusão. Não faz muito sentido pedir a entrada de nome e endereço se precisamos apenas do telefone (chave do arquivo). Como observações temos a definição da cor diferente para a entrada do telefone que é utilizada por todos os níveis inferiores. E também dois dos problemas que considero no gnuCOBOL 1 (ainda não solucionados na versão 2). O primeiro é a impossibilidade de entrada da direita para a esquerda que é interessante para valores númericos bem como a limpeza da variável se o primeiro caractere digitado não for de movimentação (setas). O segundo é a não verificação de REQUIRED na entrada dos dados implicando que o usuário faça a consistência via programação, isto é, não tem sentido um cadastro de clientes sem o nome do cliente.

Finalmente temos ss-erro que mostra na linha de rodapé uma mensagem de erro e espera que o usuário pressione enter.

INICIO

Informamos algumas variáveis de ambiente para o programa se comportar como desejamos. No caso, queremos que ele interprete as teclas especiais (principalmente Esc). Como o tempo de espera é muito pequena (1 segundo) e a velocidade dos terminais hoje é muito maior, definimos o tempo em milisegundos (poderíamos ter definido no próprio ambiente, no caso do Linux EXPORT escdelay=25, por exemplo) . Depois obtemos o número de linhas e colunas disponíveis no termina e abrimos o arquivo (que será visto posteriormente).

O próximo passo é o laço para que o usuário selecione a opção desejada e o programa execute a rotina correspondente. Ajustamos e mostramos o cabeçalho e rodapé e esperamos a digitação por parte do usuário. Note que usamos diretamente accept para a tela menu dispensando o display.

Como o ponto encerra uma sentença, é importante que se encerre determinados comandos com o respectivo end (end-if, end-evaluate, etc.). Assim, o compilador emitirá um aviso se alguma coisa estiver errada antes do programador queimar neurônios buscando um erro. Um fácil de cometer é um if com diversos comandos internos e, se existir um ponto antes do desejado, o if também terminará antes. O perform parágrafo thru parágrafo também é importante para que a rotina não seja encerrada antes do desejado.

FINALIZA

Basicamente fecha o arquivo e encerra o programa.

INCLUI

São as rotinas de inclusão dos clientes. Inicialmente ajusta e mostra a tela e entra em um loop para a inclusão do cliente. Foi utilizado GO (TO) mas, para quem acha que não pode, poderia utilizar um PERFORM como no loop do menu em inicio utilizando COB-SRC-ESC com indicador de término.

Na parte de gravação write, não foram feitas maiores verificações a assume-se que um erro seja porque a chave já existe. Note que quando você grava (write) informa o registro (file1-rec) e quando le ou exclui (read ou delete) informa o arquivo (file1).

CONSULTA

Basicamente o mesmo processo de INCLUI porém, como as rotinas de alteração, consulta e exclusão utilizam o mesmo princípio, isto é, apenas a entrada do telefone (chave), foi criada uma rotina para evitar a duplicação do processo no programa. Caso seja pressionado Esc durante a entrada da chave, a rotina coloca 99 em fs-stat indicando fs-cancela e o programa sabe que deve cancelar. Apenas para digitar menos e não precisar verificar cob-src-esc.

ALTERA

Semelhante a CONSULTA porém, após a entrada da chave, solicita a entrada do dados do cliente para a alteração. Todo o registro é regravado.

EXCLUI

Semelhante a rotina de consulta porém, após a entrada da chave a rotina mostra os dados do cliente e solicita a confirmação para a exclusão. Qualquer coisa diferente de sim (S ou s) cancela a exclusão. Só entra no laço se a chave não existe caso contrário, retorna ao menu.

LE-CLIENTE

Espera que o usuário informe a chave. Caso seja pressionado Esc, o programa retorna ajustando fs-stat para fs-cancela. Se ocorreu um erro, assume que o cliente não existe, mostra a mensagem e retorna.

ABRIR-ARQUIVOS.

Como a abertura de um arquivo para entrada e saída (I-O) pressupõe que o arquivo já exista (se for apenas para leitura também). Caso ele não exista (erro 35) o programa abre o arquivo para saída (sempre será sobrescrito), fecha e abre novamente para entrada e saída. Se deixarmos apenas para saída (output) o nosso programa só funcionar para a inclusão de clientes mas precisamos consulta, etc.. Não testamos outros erros e, nestes casos, o nosso programa não funcionará de forma adequada.

MOSTRA-ERRO

Mostra a mensagem de erro no rodapé, espera que o usuário pressione enter (ou alguma tecla e enter) e retorna o rodapé para a mensagem anterior.

Considerações finais

  • Note que você pode facilmente copiar o fonte e, com pequenas alterações, adaptar o programa para outra finalidade. Cadastro de fornecedores, por exemplo. Para facilitar ainda mais, poderíamos mover as mensagens de erro para a working-storage section onde o agrupamento permitiria as alterações com mais facilidade. Basicamente trocar cliente por fornecedor no texto.
  • A inclusão de novos campos ao registro também pode ser feito de forma relativamente simples. Basta adicioná-los ao file1-rec e inclui-os na ss-tela-registro. Como a cláusula required é aceita mas ignorada, será necessário efetuar os testes desejados na inclusão.
Anúncios