12. Trabalhando com arquivos indexados

Até aqui trabalhamos com arquivos sequenciais (ou mais precisamente arquivos sequenciais lineares), onde os registros são armazenados na ordem em que foram inseridos e que só podem ser lidos um a um. Esse tipo de arquivo é perfeito para o processamento em lote de grandes volumes de informação. Mas muitas vezes precisamos acessar registros de forma randômica – sem uma ordem pré-estabelecida – usando chaves ou índices.

Arquivos indexados permitem que seus registros sejam acessados diretamente a partir de uma ou mais chaves formadas por um ou mais campos do registro.

Fundamentos

Ao contrário da organização sequencial, que mantém todos os registros num só lugar, na organização indexada os arquivos são formados por dois componentes: uma área de dados (semelhante a um arquivo sequencial) e uma área de índices, onde os valores das chaves apontam para a localização física do registro na área de dados.

Cobol: Arquivos indexados
Figura 48. Organização de arquivos indexados

A área de índice é ordenada pelos valores das chaves que foram definidas para o arquivo. Já na área de dados, os registros são armazenados na ordem em que foram inseridos, sem nenhuma classificação pré-estabelecida.

Para ler, por exemplo, o cliente 789 da figura anterior, o programa procura o valor dessa chave (789) na área de índice, obtém a localização física do registro (14) e depois lê diretamente o conteúdo que está nessa posição, na área de dados.

Mas arquivos indexados também pode ser acessados em modo sequencial. Nesse caso, o programa lê sequencialmente a área de índices e para cada índice lido acessa a posição correspondente na área de dados. Consequentemente, mesmo que a área de dados não esteja ordenada, a leitura sequencial de um arquivo indexado sempre recuperará os registros na ordem ascendente do índice utilizado.

Cobol: Desempenho de arquivos indexados

Todo arquivo indexado deve conter pelo menos uma chave, chamada primary key ou chave primária. Não podem existir dois registros num mesmo arquivo que possuam os mesmos valores no(s) campo(s) que compõe(m) a chave primária.

Além da chave primária, arquivos indexados podem ser definidos com chaves alternativas, também conhecidas como alternate keys. As chaves alternativas podem ser únicas (como as chaves primárias) mas também podem permitir a duplicidade de registros.

Cobol: Chaves alternativas em arquivos indexados
Figura 49. Chaves alternativas em arquivos indexados

A figura acima mostra um campo chamado CD-SEGTO que foi definido como chave alternativa. Repare que a área de índices possui um mesmo valor desse campo sendo associado a mais de um registro.

Quando um programa acessa um arquivo indexado de forma randômica por uma chave alternativa que permita duplicidade, apenas o primeiro registro que possui essa chave é recuperado. Na figura anterior, se um programa tentasse ler o arquivo informando “SRV” para a chave CD-SEGTO, apenas o registro na posição 7 seria recuperado. Para acessar os demais registros o programa teria que continuar a leitura em modo sequencial.

Declarando arquivos indexados

Arquivos indexados são declarados na ENVIRONMENT DIVISION, como qualquer outro arquivo convencional. A diferença em relação às declarações que vimos até agora é que precisamos indicar qual é sua chave primária (obrigatória) e quais são suas chaves alternativas (opcionais). O exemplo abaixo mostra a declaração de um arquivo indexado que não tem chaves alternativas:

ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
    SPECIAL-NAMES.
        DECIMAL POINT IS COMMA.

INPUT-OUTPUT SECTION.
FILE-CONTROL.

    SELECT arquivo ASSIGN TO nome-externo
        ORGANIZATION IS INDEXED
        ACCESS MODE IS DYNAMIC
        RECORD KEY IS nome-do-campo1
        FILE STATUS IS nome-da-variavel.

Já o exemplo abaixo mostra a declaração de um arquivo indexado que possui duas chaves alternativas:

ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
    SPECIAL-NAMES.
        DECIMAL POINT IS COMMA.

INPUT-OUTPUT SECTION.
FILE-CONTROL.

    SELECT arquivo ASSIGN TO nome-externo
        ORGANIZATION IS INDEXED
        ACCESS MODE IS DYNAMIC
        RECORD KEY IS nome-do-campo1
        ALTERNATE RECORD KEY IS nome-do-campo2
        ALTERNATE RECORD KEY IS nome-do-campo3 WITH DUPLICATES
        FILE STATUS IS nome-da-variavel.

A opção WITH DUPLICATES da cláusula ALTERNATE RECORD KEY informa que a chave permite duplicidade. Se essa opção for omitida, o programa assume que a chave é única.

A cláusula ACCESS MODE indica como o programa acessará o arquivo. Ela permite as seguintes \opções:

  • ACCESS MODE IS SEQUENTIAL: O programa vai escolher uma das chaves (a primária ou uma das alternativas) e lerá os registros sequencialmente usando essa chave.
  • ACCESS MODE IS RANDOM: O programa vai escolher uma das chaves (a primária ou uma das alternativas), informar um valor para essa chave e acessar diretamente (randomicamente) o primeiro registro associado a esse valor
  • ACCESS MODE IS DYNAMIC: O programa poderá acessar o arquivo tanto no modo sequencial quanto no modo randômico.

Se a cláusula ACCESS MODE for omitida, o programa assume que o acesso será sequencial. O mais comum é que se crie um book para declarar o arquivo indexado usando o modo DYNAMIC, uma vez que com isso esse book poderia ser usado tanto por programas que acessem o arquivo em modo sequencial quanto por programas que precisem acessá-lo em modo randômico.

O uso do File Status em arquivos indexados

A variável associada à cláusula FILE STATUS na declaração do arquivo é igual às que criamos para arquivos sequenciais: alfanumérica de duas posições. Como também acontecia com os arquivos sequenciais, essa variável é atualizada a cada operação de I/O que realizamos sobre o arquivo, inclusive na sua abertura e fechamento.

Cobol: File Status
Figura 50. Valores mais comuns para FILE STATUS de arquivos indexados

Alguns dos erros mencionados acima podem ser recuperados pelo próprio programa. Em um programa on-line, por exemplo, é comum receber o erro 23 no comando READ que tentou ler uma chave que o usuário informou incorretamente.

Outros erros são irrecuperável e exigem que o programa interrompa o processamento. Por exemplo, um erro 39 significa que o programa declarou um arquivo indexado mas o que o programa encontrou no ambiente foi um arquivo com organização sequencial. Um erro 47 significa que o programa tentou fazer um READ num arquivo que foi aberto com OPEN OUTPUT… Essas situações, normalmente, são tratadas com uma mensagem de erro e um fim de processamento anormal.

Detalhando arquivos indexados

A file description (FD) de um arquivo indexado na DATA DIVISION é igual às que vimos até agora. O único ponto que merece atenção é que todos os campos mencionados na RECORD KEY ou na(s) ALTERNATE RECORD KEY(s) da cláusula SELECT precisam ser declarados explicitamente no layout do registro:

SELECT CRA0201 ASSIGN TO “$DAT/CRA0201”
    ORGANIZATION IS INDEXED
    ACCESS MODE IS DYNAMIC
    RECORD KEY IS CRA0201-CD-CLIENTE
    ALTERNATE RECORD KEY IS CRA0201-CD-SEGMENTO WITH DUPLICATES
    ALTERNATE RECORD KEY IS CRA0201-NR-CNPJ WITH DUPLICATES
    FILE STATUS IS WT-ST-CRA0201.

...

FD CRA0201.
01 CRA0201-REGISTRO.
    03 CRA0201-CD-CLIENTE          PIC X(006).
    03 CRA0201-NM-CLIENTE          PIC X(045).
    03 CRA0201-NM-LOGRADOURO       PIC X(045).
    03 CRA0201-NM-BAIRRO           PIC X(020).
    03 CRA0201-NM-CIDADE           PIC X(020).
    03 CRA0201-CD-ESTADO           PIC X(002).
    03 CRA0201-NR-TELEFONE-1       PIC X(020).
    03 CRA0201-NR-TELEFONE-2       PIC X(020).
    03 CRA0201-NM-EMAIL            PIC X(030).
    03 CRA0201-NR-CNPJ             PIC 9(014).
    03 CRA0201-CD-SEGMENTO         PIC X(003).

É uma boa prática de programação destacar, na FD, quais são as chaves primárias e as chaves alternativas do arquivo, mesmo quando elas são formadas por itens elementares, como no exemplo acima. Um detalhamento melhor desse arquivo poderia ser:

SELECT CRA0201 ASSIGN TO “$DAT/CRA0201”
    ORGANIZATION IS INDEXED
    ACCESS MODE IS DYNAMIC
    RECORD KEY IS CRA0201-CHAVE-1
    ALTERNATE RECORD KEY IS CRA0201-CHAVE-2 WITH DUPLICATES
    ALTERNATE RECORD KEY IS CRA0201-CHAVE-3 WITH DUPLICATES
    FILE STATUS IS WT-ST-CRA0201.

...

FD CRA0201.
01 CRA0201-REGISTRO.
    03 CRA0201-CHAVE-1.
        05 CRA0201-CD-CLIENTE      PIC X(006).
    03 CRA0201-NM-CLIENTE          PIC X(045).
    03 CRA0201-NM-LOGRADOURO       PIC X(045).
    03 CRA0201-NM-BAIRRO           PIC X(020).
    03 CRA0201-NM-CIDADE           PIC X(020).
    03 CRA0201-CD-ESTADO           PIC X(002).
    03 CRA0201-NR-TELEFONE-1       PIC X(020).
    03 CRA0201-NR-TELEFONE-2       PIC X(020).
    03 CRA0201-NM-EMAIL            PIC X(030).
    03 CRA0201-CHAVE-2.
        05 CRA0201-NR-CNPJ         PIC 9(014).
    03 CRA0201-CHAVE-3.
        05 CRA0201-CD-SEGMENTO            PIC X(003).

Chaves primárias e alternativas podem ser compostas, isto é, formadas por mais de um campo do registro. No exemplo abaixo, a chave primária do arquivo é formada pelos campos NR-FATURA e NR-DUPLICATA:

SELECT CRA0202 ASSIGN TO “$DAT/CRA0202”
    ORGANIZATION IS INDEXED
    ACCESS MODE IS DYNAMIC
    RECORD KEY IS CRA0202-CHAVE-1
    FILE STATUS IS WT-ST-CRA0202.

...

FD CRA0202.
01 CRA0202-REGISTRO.
    03 CRA0202-CHAVE-1.
        05 CRA0201-NR-FATURA       PIC  9(006).
        05 CRA0201-NR-DUPLICATA     PIC  9(002).
    03 CRA0201-CD-CLIENTE          PIC  X(006).
    03 CRA0201-DT-EMISSAO          PIC  9(008).
    03 CRA0201-DT-VENCIMENTO       PIC  9(008).
    03 CRA0201-VL-DUPLICATA        PIC S9(013)V9(002).
    03 CRA0201-CD-CATEGORIA        PIC  X(003).
    03 CRA0201-ST-DUPLICATA        PIC  X(003).

Lendo arquivos indexados em modo randômico

A leitura direta – aquela que traz um único registro associado a uma chave informada – é a forma mais simples de acesso a um arquivo indexado. Vamos ver como isso acontece alterando um dos programas que já construímos nesse livro: FAP0501.

Esse programa gerou o seguinte relatório:

EMPRESA XYZ                                                       DATA: 14/01/17
FATURAMENTO                                                       HORA: 09:29:37
FAL0501                       VENDAS POR VENDEDOR                 PAGINA:      1
--------------------------------------------------------------------------------
VENDEDOR       DATA         CLIENTE      FATURA                            VALOR
--------------------------------------------------------------------------------
000001       11/05/2015     001240       015001                        21.250,00
             11/05/2015     002304       015002                        74.750,00
             13/05/2015     000988       015005                        25.790,00
                                                                    ------------
                                                           TOTAL:     121.790,00

000002       11/05/2015     001700       015003                       116.414,00
             12/05/2015     002800       015004                         8.515,00
                                                                    ------------
                                                           TOTAL:     124.929,00

000003       14/05/2015     003501       015006                         1.600,00
                                                                    ------------
                                                           TOTAL:       1.600,00

000004       15/05/2015     000515       015007                        35.300,00
             15/05/2015     000789       015009                         7.280,00
             15/05/2015     000901       015011                        41.200,00
             15/05/2015     001330       015012                         8.920,00
                                                                    ------------
                                                           TOTAL:      92.700,00

000005       15/05/2015     001514       015008                         6.665,00
             15/05/2015     002201       015010                        12.458,00
             16/05/2015     001101       015013                         1.740,00
                                                                    ------------
                                                           TOTAL:      20.863,00

000006       16/05/2015     002005       015014                        64.300,00
                                                                    ------------
                                                           TOTAL:      64.300,00

Vamos alterar esse relatório para exibir o nome do cliente no lugar do código do cliente. Para isso, teremos que deslocar o número da fatura para a direita para abrir espaço para o novo campo. O novo layout do relatório ficará assim:

EMPRESA XYZ                                                       DATA: 99/99/99
FATURAMENTO                                                       HORA: 99:99:99
FAL0501                       VENDAS POR VENDEDOR                 PAGINA:    ZZ9
--------------------------------------------------------------------------------
VENDEDOR       DATA         CLIENTE                          FATURA        VALOR
--------------------------------------------------------------------------------
999999       99/99/9999     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX   999999   ZZZ.ZZ9,99
             99/99/9999     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX   999999   ZZZ.ZZ9,99
                                                                    ------------
                                                           TOTAL:   Z.ZZZ.ZZ9,99

999999       99/99/9999     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX   999999   ZZZ.ZZ9,99
             99/99/9999     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX   999999   ZZZ.ZZ9,99
                                                                    ------------
                                                           TOTAL:   Z.ZZZ.ZZ9,99

O nome do cliente está num arquivo indexado chamado CRA0201. O book de declaração do arquivo se chama CRS0201, que tem o seguinte conteúdo:

      *----------------------------------------------------------------*
      * CADASTRO DE CLIENTES
      *----------------------------------------------------------------*
           SELECT CRA0201 ASSIGN TO "$DAT/CRA0201.DAT"
               ORGANIZATION IS INDEXED        
               ACCESS MODE IS DYNAMIC
               RECORD KEY IS CRA0201-CHAVE-1
               ALTERNATE RECORD KEY IS CRA0201-CHAVE-2 WITH DUPLICATES
               ALTERNATE RECORD KEY IS CRA0201-CHAVE-3 WITH DUPLICATES
               FILE STATUS IS WT-ST-CRA0201.

O book de detalhamento do arquivo se chama CRF0201:

FD CRA0201.
01 CRA0201-REGISTRO.
    03 CRA0201-CHAVE-1.
        05 CRA0201-CD-CLIENTE      PIC X(006).
    03 CRA0201-NM-CLIENTE          PIC X(045).
    03 CRA0201-NM-LOGRADOURO       PIC X(045).
    03 CRA0201-NM-BAIRRO           PIC X(020).
    03 CRA0201-NM-CIDADE           PIC X(020).
    03 CRA0201-CD-ESTADO           PIC X(002).
    03 CRA0201-NR-TELEFONE-1       PIC X(020).
    03 CRA0201-NR-TELEFONE-2       PIC X(020).
    03 CRA0201-NM-EMAIL            PIC X(030).
    03 CRA0201-CHAVE-2.
        05 CRA0201-NR-CNPJ         PIC 9(014).
    03 CRA0201-CHAVE-3.
        05 CRA0201-CD-SEGMENTO            PIC X(003).

Vamos começar justamente inserindo o book de declaração na ENVIRONMENT DIVISION:

      *================================================================*
       ENVIRONMENT DIVISION.
      *----------------------------------------------------------------*
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
           DECIMAL-POINT IS COMMA.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

      * VENDAS MENSAIS
           COPY FAS0500.

      * CADASTRO DE CLIENTES
           COPY CRS0201.

      * ARQUIVO TEMPORARIO PARA CLASSIFICACAO
          SELECT SRT0500 ASSIGN TO "$DAT/SRT0500.DAT"
              ORGANIZATION IS LINE SEQUENTIAL.
        
      * RELATORIO DE VENDAS POR VENDEDOR      
           SELECT FAL0501 ASSIGN TO "$DAT/FAL0501.TXT"
               ORGANIZATION IS LINE SEQUENTIAL.

E o book de detalhamento na DATA DIVISION:

      *================================================================*
       DATA DIVISION.
      *----------------------------------------------------------------*
       FILE SECTION.

      * VENDAS MENSAIS
           COPY FAF0500.
       
      * CADASTRO DE CLIENTES
           COPY CRF0201.

      * ARQUIVO TEMPORARIO PARA CLASSIFICACAO
       SD SRT0500.
       01 SRT0500-REGISTRO.
           03 SRT0500-NR-VENDEDOR      PIC 9(006).
           03 FILLER                   PIC X(035).
    
      * RELATORIO DE VENDAS POR VENDEDOR
       FD FAL0501.
       01 FAL0501-REGISTRO             PIC  X(080).

Como temos um novo arquivo no programa, precisamos criar uma variável na WORKING para o file status das operações que realizaremos sobre ele:

       01 WT-FILE-STATUS.
           03 WT-ST-FAA0500            PIC  X(002).
           03 WT-ST-CRA0201            PIC  X(002).

Agora vamos alterar a linha detalhe e a linha que contém o título das colunas para inserir o nome do cliente e deslocar o número da fatura para a direita:

       01 WR-CAB4.
           03  FILLER                  PIC X(015) VALUE "VENDEDOR".
           03  FILLER                  PIC X(013) VALUE "DATA".
           03  FILLER                  PIC X(013) VALUE "CLIENTE".
           03  FILLER                  PIC X(033) VALUE "CLIENTE".
           03  FILLER                  PIC X(034) VALUE "FATURA".
           03  FILLER                  PIC X(014) VALUE "FATURA".
           03  FILLER                  PIC X(005) VALUE "VALOR".

       01 WR-DET1.
           03  WR-DET-NR-VENDEDOR      PIC 9(006) VALUE ZEROS
               BLANK WHEN ZEROS.
           03  FILLER                  PIC X(007) VALUE SPACES.
           03  WR-DET-DT-VENDA         PIC X(010) VALUE SPACES.
           03  FILLER                  PIC X(005) VALUE SPACES.
           03  WR-DET-CD-CLIENTE       PIC X(006) VALUE SPACES.
           03  WR-DET-NM-CLIENTE       PIC X(030) VALUE SPACES.
           03  FILLER                  PIC X(007) VALUE SPACES.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-NR-FATURA        PIC 9(006) VALUE ZEROS.
           03  FILLER                  PIC X(023) VALUE SPACES.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-VL-VENDA         PIC ZZZ.ZZ9,99 VALUE ZEROS.

O arquivo CRA0201 precisa ser aberto no parágrafo inicial junto com os outros arquivos. Ele será aberto em modo INPUT pois só pretendemos ler os seus registros:

      *----------------------------------------------------------------*
      * CLASSIFICA O ARQUIVO DE ENTRADA POR NUMERO DO VENDEDOR. EM SE-
      * GUIDA, ABRE OS ARQUIVOS E LE O PRIMEIRO REGISTRO DO ARQUIVO DE
      * ENTRADA
      *----------------------------------------------------------------*
       1-INICIA.

           SORT SRT0500
               ON ASCENDING KEY SRT0500-NR-VENDEDOR
               USING FAA0500
               GIVING FAA0500

           OPEN INPUT FAA0500
           OPEN INPUT CRA0201
           OPEN OUTPUT FAL0501

           READ FAA0500.

Agora vamos procurar o parágrafo que imprime a linha detalhe e substituir a movimentação do código do cliente pela movimentação do nome do cliente. Mas antes disso vamos inserir o comando de leitura.

A leitura randômica de arquivos indexados também é realizada com o comando READ. A única diferença é que antes do comando precisamos mover o valor da chave que pretendemos ler.

No nosso caso, ao invés de mover o código do cliente para o relatório, vamos mover esse código para a chave primária do cadastro de clientes, fazer a leitura, verificar se a leitura foi bem sucedida e mover o nome do cliente para o relatório:

      *----------------------------------------------------------------*
      * IMPRIME TODAS AS VENDAS DO VENDEDOR
      *----------------------------------------------------------------*
       21-IMPRIME-VENDAS.

           IF WT-CT-LINHAS > WC-LINHAS-POR-PAGINA
               PERFORM X1-IMPRIME-CABECALHO
           END-IF
        
           CALL WT-NM-EDT4 USING FAA0500-DT-VENDA  
                                 WR-DET-DT-VENDA  
                                 WT-RC-EDT4

           MOVE FAA0500-CD-CLIENTE TO WR-DET-NM-CLIENTE
           MOVE FAA0500-CD-CLIENTE TO CRA0201-CD-CLIENTE
           READ CRA0201
           IF WT-ST-CRA0201 = “00”
              MOVE CRA0201-NM-CLIENTE TO WR-DET-NM-CLIENTE
           ELSE
              MOVE “*** NAO ENCONTRADO ***” TO WR-DET-NM-CLIENTE
           END-IF

           MOVE FAA0500-NR-FATURA TO WR-DET-NR-FATURA
           MOVE FAA0500-VL-VENDA TO WR-DET-VL-VENDA 
        
           WRITE FAL0501-REGISTRO FROM WR-DET1
           ADD 1 TO WT-CT-LINHAS
           ADD FAA0500-VL-VENDA TO WT-AC-VENDAS    

           MOVE ZEROS TO WR-DET-NR-VENDEDOR

           READ FAA0500.

Repare que depois da leitura estamos testando o file status da operação. Se o file status for qualquer coisa diferente de “00” nós mostraremos “*** NAO ENCONTRADO ***” no nome do cliente. Essa é uma forma “preguiçosa” de proteger o programa contra erros de leitura. O ideal seria testar o file status e…

  • Mover o nome do cliente para o relatório quando file status fosse igual a “00”
  • Mover “*** NAO ENCONTRADO ***” para o nome do cliente quando o file status fosse igual a “23” (registro não encontrado)
  • Exibir uma mensagem de erro e interromper o programa quando o file status tivesse qualquer outro valor; erro não previsto que precisa ser investigado

Como aqui só queremos mostrar o uso de leitura em arquivos indexados, vamos ficar com a forma preguiçosa mesmo.

O comando READ para arquivos indexados possui um outro formato que poderíamos ter usado nesse parágrafo:

READ arquivo
    INVALID KEY
        Comando-1
        Comando-2
        Comando-3
    NOT INVALID KEY
        Comando-4
        Comando-5
        Comando-6
END-READ

Os comandos do bloco INVALID KEY são executados sempre que a leitura é mal sucedida, equivalente ao file status diferente de “00”. Os comandos do bloco NOT INVALID KEY são executados com a leitura é realizada com sucesso, equivalente ao file status igual a “00”.

No nosso exemplo ficaria assim:

           MOVE FAA0500-CD-CLIENTE TO CRA0201-CD-CLIENTE
           READ CRA0201
               INVALID KEY
                   MOVE “*** NAO ENCONTRADO *** TO WR-DET-NM-CLIENTE
               NOT INVALID KEY
                   MOVE CRA0201-NM-CLIENTE TO WR-DET-NM-CLIENTE
           END-READ

O formato simples, com teste de file status, te dará mais liberdade. Se amanhã você quiser fazer um tratamento mais completo para diferentes valores de file status, a solução com IF ficará mais simples e clara.

Nossa última alteração será no parágrafo de término do programa, onde fecharemos o cadastro de clientes:

     *----------------------------------------------------------------*
     * FECHA ARQUIVOS
     *----------------------------------------------------------------*
      3-TERMINA.

          CANCEL WT-NM-EDT4

          CLOSE FAA0500 FAL0501 CRA0201.

Nosso programa completo ficou assim:

      *================================================================*
       IDENTIFICATION DIVISION.
      *----------------------------------------------------------------*
       PROGRAM-ID.    FAP0501.
       AUTHOR.        PAULO ANDRE DIAS.
       DATE-WRITTEN.  14/01/2017.
       REMARKS.
      *----------------------------------------------------------------*
      * SISTEMA:      FA - FATURAMENTO      
      * JOB:          05 - RELATORIOS              
      * PROGRAMA:     01 - VENDAS POR VENDEDOR     
      *
      * OBJETIVO:     LER O ARQUIVO DE VENDAS NO MES E GERAR RELATORIO
      *               DE VENDAS POR VENDEDOR
      *                   
      * VERSOES:      DATA    DESCRICAO
      *               ------  ---------------------------------------
      *               XXXXXX  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      *
      *----------------------------------------------------------------*

      *================================================================*
       ENVIRONMENT DIVISION.
      *----------------------------------------------------------------*
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
           DECIMAL-POINT IS COMMA.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

      * VENDAS MENSAIS
           COPY FAS0500.

      * CADASTRO DE CLIENTES
           COPY CRS0201.

      * ARQUIVO TEMPORARIO PARA CLASSIFICACAO
          SELECT SRT0500 ASSIGN TO "$DAT/SRT0500.DAT"
              ORGANIZATION IS LINE SEQUENTIAL.
       
      * RELATORIO DE VENDAS POR VENDEDOR      
           SELECT FAL0501 ASSIGN TO "$DAT/FAL0501.TXT"
               ORGANIZATION IS LINE SEQUENTIAL.

      *================================================================*
       DATA DIVISION.
      *----------------------------------------------------------------*
       FILE SECTION.

      * VENDAS MENSAIS
           COPY FAF0500.
        
      * CADASTRO DE CLIENTES
           COPY CRF0201.

      * ARQUIVO TEMPORARIO PARA CLASSIFICACAO
       SD SRT0500.
       01 SRT0500-REGISTRO.
           03 SRT0500-NR-VENDEDOR      PIC 9(006).
           03 FILLER                   PIC X(035).
   
      * RELATORIO DE VENDAS POR VENDEDOR
       FD FAL0501.
       01 FAL0501-REGISTRO             PIC  X(080).

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WC-CONSTANTES.
           03 WC-LINHAS-POR-PAGINA     PIC  9(002) VALUE 60.
    
       01 WT-FILE-STATUS.
           03 WT-ST-FAA0500            PIC  X(002) VALUE SPACES.
           03 WT-ST-CRA0201            PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
           03 WT-CT-LINHAS             PIC  9(002) VALUE 99.

       01 WT-ACUMULADORES.
           03 WT-AC-VENDAS             PIC S9(013)V9(002) VALUE ZEROS.

       01 WT-AUXILIARES.
           03 WT-NM-EDT4               PIC X(008) VALUE "XXREDT4".
           03 WT-RC-EDT4               PIC 9(002) VALUE ZEROS.
           03 WT-DT-SISTEMA.
              05 ANO                   PIC 9(002) VALUE ZEROS.
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 DIA                   PIC 9(002) VALUE ZEROS.
           03 WT-HR-SISTEMA.
              05 HORA                  PIC 9(002) VALUE ZEROS.
              05 MINUTO                PIC 9(002) VALUE ZEROS.
              05 SEGUNDO               PIC 9(002) VALUE ZEROS.
    
       01 WT-CAMPOS-CONTROLE.
           03 WT-CTL-NR-VENDEDOR       PIC 9(006) VALUE ZEROS.

       01 WR-CAB1.
           03 FILLER                   PIC X(066) VALUE
              "EMPRESA XYZ".
           03 FILLER                   PIC X(006) VALUE
              "DATA: ".
           03 WR-CAB-DATA.
              05 DIA                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 MES                   PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE "/".
              05 ANO                   PIC 9(002) VALUE ZEROS.

       01 WR-CAB2.
           03 FILLER                   PIC X(066) VALUE
              "FATURAMENTO".
           03 FILLER                   PIC X(006) VALUE
              "HORA: ".
           03 WR-CAB-HORA.
              05 HORA                  PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE ":".
              05 MINUTO                PIC 9(002) VALUE ZEROS.
              05 FILLER                PIC X(001) VALUE ":".
              05 SEGUNDO               PIC 9(002) VALUE ZEROS.

       01 WR-CAB3.
           03 FILLER                   PIC X(030) VALUE
              "FAL0501".
           03 FILLER                   PIC X(036) VALUE
              "VENDAS POR VENDEDOR".
           03 FILLER                   PIC X(011) VALUE
              "PAGINA: ".
           03 WR-CAB-PAGINA            PIC ZZ9 VALUE
              ZEROS.

       01 WR-SEP1.
           03  FILLER                  PIC X(080) VALUE ALL "-".

       01 WR-CAB4.
           03  FILLER                  PIC X(015) VALUE "VENDEDOR".
           03  FILLER                  PIC X(013) VALUE "DATA".
           03  FILLER                  PIC X(033) VALUE "CLIENTE".
           03  FILLER                  PIC X(014) VALUE "FATURA".
           03  FILLER                  PIC X(005) VALUE "VALOR".

       01 WR-DET1.
           03  WR-DET-NR-VENDEDOR      PIC 9(006) VALUE ZEROS
               BLANK WHEN ZEROS.
           03  FILLER                  PIC X(007) VALUE SPACES.
           03  WR-DET-DT-VENDA         PIC X(010) VALUE SPACES.
           03  FILLER                  PIC X(005) VALUE SPACES.
           03  WR-DET-NM-CLIENTE       PIC X(030) VALUE SPACES.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-NR-FATURA        PIC 9(006) VALUE ZEROS.
           03  FILLER                  PIC X(003) VALUE SPACES.
           03  WR-DET-VL-VENDA         PIC ZZZ.ZZ9,99 VALUE ZEROS.

       01 WR-ROD1.
           03  FILLER                  PIC X(068) VALUE SPACES.
           03  FILLER                  PIC X(012) VALUE ALL "-".

       01 WR-ROD2.
           03  FILLER                  PIC X(059) VALUE SPACES.
           03  FILLER                  PIC X(009) VALUE
               "TOTAL: ".
           03  WR-ROD-AC-VENDAS        PIC Z.ZZZ.ZZ9,99 VALUE ZEROS.

      *================================================================*
       PROCEDURE DIVISION.
      *----------------------------------------------------------------*
       0-PRINCIPAL.

           PERFORM 1-INICIA
           PERFORM 2-PROCESSA UNTIL WT-ST-FAA0500 NOT = "00"
           PERFORM 3-TERMINA

           STOP RUN.

      *----------------------------------------------------------------*
      * CLASSIFICA O ARQUIVO DE ENTRADA POR NUMERO DO VENDEDOR. EM SE-
      * GUIDA, ABRE OS ARQUIVOS E LE O PRIMEIRO REGISTRO DO ARQUIVO DE
      * ENTRADA
      *----------------------------------------------------------------*
       1-INICIA.

           SORT SRT0500
               ON ASCENDING KEY SRT0500-NR-VENDEDOR
               USING FAA0500
               GIVING FAA0500

           OPEN INPUT FAA0500
           OPEN INPUT CRA0201
           OPEN OUTPUT FAL0501

           READ FAA0500.

      *----------------------------------------------------------------*
      * SALVA O CAMPO DE CONTROLE (NUMERO DO VENDEDOR) IMPRIME TODAS
      * AS SUAS VENDAS E IMPRIME SEU TOTAL DE VENDAS NO PERIODO
      *----------------------------------------------------------------*
       2-PROCESSA.

           MOVE FAA0500-NR-VENDEDOR TO WT-CTL-NR-VENDEDOR
           MOVE FAA0500-NR-VENDEDOR TO WR-DET-NR-VENDEDOR
           MOVE ZEROS TO WT-AC-VENDAS

           PERFORM 21-IMPRIME-VENDAS
               UNTIL WT-ST-FAA0500 NOT = "00" OR
                     FAA0500-NR-VENDEDOR NOT = WT-CTL-NR-VENDEDOR

           PERFORM 22-IMPRIME-TOTAL.

      *----------------------------------------------------------------*
      * FECHA ARQUIVOS
      *----------------------------------------------------------------*
       3-TERMINA.

           CANCEL WT-NM-EDT4

           CLOSE FAA0500 FAL0501 CRA0201.

      *----------------------------------------------------------------*
      * IMPRIME TODAS AS VENDAS DO VENDEDOR
      *----------------------------------------------------------------*
       21-IMPRIME-VENDAS.

           IF WT-CT-LINHAS > WC-LINHAS-POR-PAGINA
               PERFORM X1-IMPRIME-CABECALHO
           END-IF
        
           CALL WT-NM-EDT4 USING FAA0500-DT-VENDA  
                                 WR-DET-DT-VENDA  
                                 WT-RC-EDT4

           MOVE FAA0500-CD-CLIENTE TO CRA0201-CD-CLIENTE
           READ CRA0201
           IF WT-ST-CRA0201 = "00"
               MOVE CRA0201-NM-CLIENTE TO WR-DET-NM-CLIENTE
           ELSE
               MOVE "*** NAO ENCONTRADO ***" TO WR-DET-NM-CLIENTE
           END-IF

           MOVE FAA0500-NR-FATURA TO WR-DET-NR-FATURA
           MOVE FAA0500-VL-VENDA TO WR-DET-VL-VENDA 
          
           WRITE FAL0501-REGISTRO FROM WR-DET1
           ADD 1 TO WT-CT-LINHAS
           ADD FAA0500-VL-VENDA TO WT-AC-VENDAS    

           MOVE ZEROS TO WR-DET-NR-VENDEDOR

           READ FAA0500.

      *----------------------------------------------------------------*
      * IMPRIME TOTAL POR VENDEDOR
      *----------------------------------------------------------------*
       22-IMPRIME-TOTAL.  

           IF WT-CT-LINHAS > WC-LINHAS-POR-PAGINA
               PERFORM X1-IMPRIME-CABECALHO
           END-IF

           MOVE WT-AC-VENDAS TO WR-ROD-AC-VENDAS

           WRITE FAL0501-REGISTRO FROM WR-ROD1
           WRITE FAL0501-REGISTRO FROM WR-ROD2 BEFORE 2
           ADD 3 TO WT-CT-LINHAS.

      *----------------------------------------------------------------*
      * IMPRIME CABECALHO
      *----------------------------------------------------------------*
       X1-IMPRIME-CABECALHO.

           ACCEPT WT-DT-SISTEMA FROM DATE
           ACCEPT WT-HR-SISTEMA FROM TIME
           ADD 1 TO WT-CT-PAGINA

           MOVE CORR WT-DT-SISTEMA TO WR-CAB-DATA
           MOVE CORR WT-HR-SISTEMA TO WR-CAB-HORA
           MOVE WT-CT-PAGINA TO WR-CAB-PAGINA

           WRITE FAL0501-REGISTRO FROM WR-CAB1 AFTER PAGE
           WRITE FAL0501-REGISTRO FROM WR-CAB2
           WRITE FAL0501-REGISTRO FROM WR-CAB3
           WRITE FAL0501-REGISTRO FROM WR-SEP1
           WRITE FAL0501-REGISTRO FROM WR-CAB4
           WRITE FAL0501-REGISTRO FROM WR-SEP1
        
           MOVE 6 TO WT-CT-LINHAS.

E o relatório FAL0501.TXT, depois das alterações, ficou assim:

EMPRESA XYZ                                                       DATA: 20/01/17
FATURAMENTO                                                       HORA: 09:22:52
FAL0501                       VENDAS POR VENDEDOR                 PAGINA:      1
--------------------------------------------------------------------------------
VENDEDOR       DATA         CLIENTE                          FATURA        VALOR
--------------------------------------------------------------------------------
000001       11/05/2015     IMOBILIARIA DEDO DE DEUS         015001    21.250,00
             11/05/2015     OLIVEIRA SANTOS CONTABILIDADE    015002    74.750,00
             13/05/2015     PAPELARIA OURO PRETO             015005    25.790,00
                                                                    ------------
                                                           TOTAL:     121.790,00

000002       11/05/2015     PROMOLIGHT EVENTOS               015003   116.414,00
             12/05/2015     CONSTRUTORA JJR                  015004     8.515,00
                                                                    ------------
                                                           TOTAL:     124.929,00

000003       14/05/2015     ALTO DROGARIAS                   015006     1.600,00
                                                                    ------------
                                                           TOTAL:       1.600,00

000004       15/05/2015     FARID ELETROMOVEIS               015007    35.300,00
             15/05/2015     POLICLININCA IMBUI               015009     7.280,00
             15/05/2015     SUPERMERCADO ABC                 015011    41.200,00
             15/05/2015     CONFECCAO TERESOPOLIS            015012     8.920,00
                                                                    ------------
                                                           TOTAL:      92.700,00

000005       15/05/2015     CONDOMINIO GREEN VILLAGE         015008     6.665,00
             15/05/2015     TEREPOINT PECAS E AUTOPECAS      015010    12.458,00
             16/05/2015     SUPERMERCADO ITAMARKET           015013     1.740,00
                                                                    ------------
                                                           TOTAL:      20.863,00

000006       16/05/2015     CASA COLORIDA MOVEIS             015014    64.300,00
                                                                    ------------
                                                           TOTAL:      64.300,00

Gravando, alterando e apagando registros

A possibilidade de acessar registros diretamente a partir de chaves ou índices faz do arquivo indexado a opção mais indicada quando precisamos gravar, alterar e/ou apagar registros randomicamente e não temos acesso a um banco de dados.

Para mostrar como realizar essas operações, vamos construir um programa simples que lê um arquivo sequencial e gera um arquivo indexado.

O arquivo de entrada é um arquivo sequencial linear, cuja declaração está disponível no book CRS0200 e que tem o seguinte conteúdo:

      *----------------------------------------------------------------*
      * INTERFACE PARA ATUALIZACAO DO CADASTRO DE CLIENTES
      *----------------------------------------------------------------*
           SELECT CRA0200 ASSIGN TO "$DAT/CRA0200.DAT"
               ORGANIZATION IS LINE SEQUENTIAL
               FILE STATUS IS WT-ST-CRA0200.

Seu layout está detalhado no book CRF0200. O primeiro campo, TP-OPERACAO, nos diz o que será feito com o registro: “I” significa que ele deve ser incluído, “A” significa que ele deve ser alterado e “E” significa que ele deve ser excluído.

      *----------------------------------------------------------------*
      * INTERFACE PARA ATUALIZACAO DO CADASTRO DE CLIENTES
      *----------------------------------------------------------------*
       FD CRA0200.
       01 CRA0200-REGISTRO.
           03 CRA0200-TP-OPERACAO          PIC  X(001).
           03 CRA0200-CD-CLIENTE           PIC  X(006).
           03 CRA0200-NM-CLIENTE           PIC  X(045).
           03 CRA0200-NM-LOGRADOURO        PIC  X(045).
           03 CRA0200-NM-BAIRRO            PIC  X(020).
           03 CRA0200-NM-CIDADE            PIC  X(020).
           03 CRA0200-CD-ESTADO            PIC  X(002).
           03 CRA0200-CD-CEP               PIC  X(008).
           03 CRA0200-NR-TELEFONE-1        PIC  X(020).
           03 CRA0200-NR-TELEFONE-2        PIC  X(020).
           03 CRA0200-NM-EMAIL             PIC  X(030).
           03 CRA0200-NR-CNPJ              PIC  9(014).
           03 CRA0200-CD-SEGMENTO          PIC  X(003).

O arquivo indexado que iremos atualizar é o mesmo que usamos no exemplo anterior. Ele será declarado com o book CRS0201 e detalhado com o book CRF0201, que vimos em nosso último programa.

A gravação, alteração e exclusão de registros acontecerá em três parágrafos diferentes, como mostrado no diagrama abaixo:

Cobol: Diagrama estruturado de programa
Figura 51. Diagrama estruturado do programa CRP0301

O parágrafo 2-PROCESSA será executado até o fim do arquivo CRA0200.

Se o campo CRA0200-TP-PROCESSO estiver preenchido com “I” o programa vai executar o parágrafo 21-INCLUI-REGISTRO para inserir um novo cliente no arquivo CRA0201.

Se o campo CRA0200-TP-PROCESSO estiver preenchido com “A” o programa vai executar o parágrafo 22-ALTERA-REGISTRO para substituir todos os campos do cliente pelo conteúdo que estiver no arquivo sequencial.

Se o campo CRA0200-TP-PROCESSO estiver preenchido com “E” o programa vai executar o parágrafo 23-EXCLUI-REGISTRO para excluir o cliente do arquivo indexado.

Para simplificar o exemplo (e focar apenas nas operações com arquivos indexados) vamos assumir que não existe possibilidade do arquivo CRA0200 ter o campo TP-PROCESSO preenchido com um valor diferente de “I”, “A” ou “E”.

Nesse programa usaremos bastante os testes com file status para verificar se todas as operações foram bem sucedidas. Se detectarmos qualquer problema nas operações de leitura, gravação, atualização ou exclusão mostraremos uma mensagem na tela do usuário indicando a operação, o tipo de erro (valor do file status) e o código do cliente que provocou o problema. Se a operação for bem sucedida (file status “00”) diremos apenas que o registro foi incluído ou alterado ou excluído.

No final do programa, exibiremos a quantidade de registros lidos, gravados, alterados e excluídos.

Da IDENTIFICATION até o FILE SECTION não há nenhuma novidade:

       *================================================================*
       IDENTIFICATION DIVISION.
      *----------------------------------------------------------------*
       PROGRAM-ID.    CRP0301.
       AUTHOR.        PAULO ANDRE DIAS.
       DATE-WRITTEN.  20/01/2017.
       REMARKS.
      *----------------------------------------------------------------*
      * SISTEMA:      CR - CONTAS A RECEBER
      * JOB:          03 - ATUALIZACAO CADASTRAL      
      * PROGRAMA:     01 - ATUALIZA CADASTRO DE CLIENTES   
      *
      * OBJETIVO:     LER ARQUIVO SEQUENCIAL E INCLUIR OU ALTERAR RE-
      *               GISTROS NO CADASTRO DE CLIENTES                
      *                   
      * VERSOES:      DATA    DESCRICAO
      *               ------  ---------------------------------------
      *               XXXXXX  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      *
      *----------------------------------------------------------------*

      *================================================================*
       ENVIRONMENT DIVISION.
      *----------------------------------------------------------------*
       CONFIGURATION SECTION.
       SPECIAL-NAMES.
           DECIMAL-POINT IS COMMA.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

      * INTERFACE DE CLIENTES PARA ATUALIZACAO
           COPY CRS0200.
   
      * CADASTRO DE CLIENTES
           COPY CRS0201.

      *================================================================*
       DATA DIVISION.
      *----------------------------------------------------------------*
       FILE SECTION.
   
      * INTERFACE DE CLIENTES PARA ATUALIZACAO
           COPY CRF0200.

      * CADASTRO DE CLIENTES
           COPY CRF0201.

Na WORKING declararemos as variáveis para file status e os contadores que exibiremos no final do programa:

      *================================================================*
       WORKING-STORAGE SECTION.
      *----------------------------------------------------------------*
       01 WT-FILE-STATUS.
           03 WT-ST-CRA0200            PIC  X(002) VALUE SPACES.
           03 WT-ST-CRA0201            PIC  X(002) VALUE SPACES.

       01 WT-CONTADORES.
           03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
           03 WT-CT-GRAVADOS           PIC  9(006) VALUE ZEROS.
           03 WT-CT-ALTERADOS          PIC  9(006) VALUE ZEROS.
           03 WT-CT-EXCLUIDOS          PIC  9(006) VALUE ZEROS.

Como previsto na especificação, o parágrafo 2-PROCESSA será executado até que não haja mais registros no arquivo de entrada:

      *================================================================*
       PROCEDURE DIVISION.
      *----------------------------------------------------------------*
       0-PRINCIPAL.

           PERFORM 1-INICIA
           PERFORM 2-PROCESSA
               UNTIL WT-ST-CRA0200 NOT = "00"       
           PERFORM 3-TERMINA

           STOP RUN.

Sabemos que os registros poderão ser gravados, alterados ou excluídos, mas não queremos apagar o conteúdo que já existir no arquivo. Por isso não podemos abrir o arquivo em modo OUTPUT. Ao invés disso, usaremos o modo I-O, que faz com que o arquivo fique disponível para operações de entrada e saída. A abertura do arquivo indexado ficará no parágrafo 1-INICIA, seguindo o padrão de codificação que estamos adotando nesse livro:

      *----------------------------------------------------------------*
      * ABRE ARQUIVOS E LE PRIMEIRO REGISTRO DO ARQUIVO DE ENTRADA    
      *----------------------------------------------------------------*
       1-INICIA.

           OPEN INPUT CRA0200
           OPEN I-O CRA0201

           READ CRA0200.

O parágrafo 2-PROCESSA avalia o valor do campo TP-PROCESSO e executa os parágrafos correspondentes para inclusão, alteração ou exclusão de registros. Para isso vamos usar o comando EVALUATE apenas por uma questão de estética, mas poderíamos também codificar um ninho com três IFs para obter o mesmo resultado. Já vimos a sintaxe do comando EVALUATE quando começamos a falar sobre programação estruturada.

O último comando do parágrafo é a leitura do próximo registro do arquivo sequencial de entrada:

      *----------------------------------------------------------------*
      * SE O CLIENTE JA' EXISTIR NO CADASTRO O REGISTRO SERA' ATUALIZA-
      * DO. SE NAO EXISTIR O REGISTRO SERA' INSERIDO
      *----------------------------------------------------------------*
       2-PROCESSA.

           ADD 1 TO WT-CT-LIDOS

           EVALUATE CRA0200-TP-OPERACAO
               WHEN "I"
                   PERFORM 21-INCLUI-REGISTRO
               WHEN "A"
                   PERFORM 22-ALTERA-REGISTRO
               WHEN "E"
                   PERFORM 23-EXCLUI-REGISTRO
           END-EVALUATE

           READ CRA0200.

No parágrafo 21-INCLUI-REGISTRO vamos mover todos os campos do arquivo de entrada para o arquivo de saída e em seguida gravar o registro no arquivo indexado usando o comando WRITE. O formato que vamos usar para o WRITE é o mesmo que usamos anteriormente para arquivos sequenciais:

      *----------------------------------------------------------------*
      * INCLUI REGISTRO NO CADASTRO DE CLIENTES
      *----------------------------------------------------------------*
       21-INCLUI-REGISTRO.

           MOVE CRA0200-CD-CLIENTE TO CRA0201-CD-CLIENTE
           MOVE CRA0200-NM-CLIENTE TO CRA0201-NM-CLIENTE
           MOVE CRA0200-NM-LOGRADOURO TO CRA0201-NM-LOGRADOURO
           MOVE CRA0200-NM-BAIRRO TO CRA0201-NM-BAIRRO
           MOVE CRA0200-NM-CIDADE TO CRA0201-NM-CIDADE
           MOVE CRA0200-CD-ESTADO TO CRA0201-CD-ESTADO
           MOVE CRA0200-CD-CEP TO CRA0201-CD-CEP
           MOVE CRA0200-NR-TELEFONE-1 TO CRA0201-NR-TELEFONE-1
           MOVE CRA0200-NR-TELEFONE-2 TO CRA0201-NR-TELEFONE-2
           MOVE CRA0200-NM-EMAIL TO CRA0201-NM-EMAIL
           MOVE CRA0200-NR-CNPJ TO CRA0201-NR-CNPJ
           MOVE CRA0200-CD-SEGMENTO TO CRA0201-CD-SEGMENTO
           WRITE CRA0201-REGISTRO

O comando WRITE para arquivos indexados possui um outro formato, um pouco mais complexo:

WRITE registro
    INVALID KEY
        Comando-1
        Comando-2
        Comando-3
    NOT INVALID KEY
        Comando-4
        Comando-5
        Comando-6
END-WRITE

No exemplo acima, o bloco de comandos 1 a 3 só seria executado quando a tentativa de gravação resultasse num file status diferente de “00”. O bloco dos comandos 4 a 6 seria executado quando file status fosse igual a “00”.  Apenas para manter uma coerência com os outros programas, aqui também preferimos testar o file status:

      *----------------------------------------------------------------*
      * INCLUI REGISTRO NO CADASTRO DE CLIENTES
      *----------------------------------------------------------------*
       21-INCLUI-REGISTRO.

           MOVE CRA0200-CD-CLIENTE TO CRA0201-CD-CLIENTE
           MOVE CRA0200-NM-CLIENTE TO CRA0201-NM-CLIENTE
           MOVE CRA0200-NM-LOGRADOURO TO CRA0201-NM-LOGRADOURO
           MOVE CRA0200-NM-BAIRRO TO CRA0201-NM-BAIRRO
           MOVE CRA0200-NM-CIDADE TO CRA0201-NM-CIDADE
           MOVE CRA0200-CD-ESTADO TO CRA0201-CD-ESTADO
           MOVE CRA0200-CD-CEP TO CRA0201-CD-CEP
           MOVE CRA0200-NR-TELEFONE-1 TO CRA0201-NR-TELEFONE-1
           MOVE CRA0200-NR-TELEFONE-2 TO CRA0201-NR-TELEFONE-2
           MOVE CRA0200-NM-EMAIL TO CRA0201-NM-EMAIL
           MOVE CRA0200-NR-CNPJ TO CRA0201-NR-CNPJ
           MOVE CRA0200-CD-SEGMENTO TO CRA0201-CD-SEGMENTO

           WRITE CRA0201-REGISTRO
           IF WT-ST-CRA0201 = "00"
               ADD 1 TO WT-CT-GRAVADOS
               DISPLAY "CLIENTE " CRA0200-CD-CLIENTE " INCLUIDO"
           ELSE
               DISPLAY "*** ERRO " WT-ST-CRA0201 
                       " NA INCLUSAO DO CLIENTE "
                       CRA0200-CD-CLIENTE
           END-IF.

Se a gravação for bem sucedida, exibiremos a seguinte mensagem na tela do usuário:

CLIENTE 999999 INCLUIDO

Se houver qualquer problema na gravação exibiremos a mensagem abaixo:

*** ERRO XX NA INCLUSAO DO CLIENTE 999999

XX será substituído pelo valor do file status. 999999 será substituído pelo código do cliente envolvido na operação.

A alteração (ou regravação) de registros em arquivos indexados é executada pelo comando REWRITE. Quando um arquivo indexado é acesso em modo sequencial (ACCESS MODE IS SEQUENTIAL) o REWRITE é executado sobre o último registro lido. Como estamos acessando o registro em modo dinâmico (ACCESS MODE IS DYNAMIC) essa leitura prévia não é necessária.

Só precisamos, portanto, mover todos os campos do arquivo de entrada para o arquivo de saída e executar o comando de regravação. Depois do comando testaremos o file status da operação de forma semelhante ao que fizemos no parágrafo anterior.

*----------------------------------------------------------------*
* ALTERA REGISTRO NO CADASTRO DE CLIENTES
*----------------------------------------------------------------*
 22-ALTERA-REGISTRO.
 
     MOVE CRA0200-CD-CLIENTE TO CRA0201-CD-CLIENTE
     MOVE CRA0200-NM-CLIENTE TO CRA0201-NM-CLIENTE
     MOVE CRA0200-NM-LOGRADOURO TO CRA0201-NM-LOGRADOURO
     MOVE CRA0200-NM-BAIRRO TO CRA0201-NM-BAIRRO
     MOVE CRA0200-NM-CIDADE TO CRA0201-NM-CIDADE
     MOVE CRA0200-CD-ESTADO TO CRA0201-CD-ESTADO
     MOVE CRA0200-CD-CEP TO CRA0201-CD-CEP
     MOVE CRA0200-NR-TELEFONE-1 TO CRA0201-NR-TELEFONE-1
     MOVE CRA0200-NR-TELEFONE-2 TO CRA0201-NR-TELEFONE-2
     MOVE CRA0200-NM-EMAIL TO CRA0201-NM-EMAIL
     MOVE CRA0200-NR-CNPJ TO CRA0201-NR-CNPJ
     MOVE CRA0200-CD-SEGMENTO TO CRA0201-CD-SEGMENTO
     REWRITE CRA0201-REGISTRO
     IF WT-ST-CRA0201 = "00"
        ADD 1 TO WT-CT-ALTERADOS
        DISPLAY "CLIENTE " CRA0200-CD-CLIENTE " ALTERADO"
     ELSE
        DISPLAY "*** ERRO " WT-ST-CRA0201
                " NA ALTERACAO DO CLIENTE "
                CRA0200-CD-CLIENTE
     END-IF.

O comando REWRITE também possui um formato com cláusulas INVALID KEY e NOT INVALID KEY, semelhante aos comandos READ e WRITE:

REWRITE registro
   INVALID KEY
      Comando-1
      Comando-2
      Comando-3
   NOT INVALID KEY
      Comando-4
      Comando-5
      Comando-6
END-REWRITE

A exclusão de registros em arquivos indexados é executada pelo comando DELETE. Ao contrário dos comandos WRITE e REWRITE, para o comando DELETE precisamos indicar o nome do arquivo cujo registro queremos deletar, e não o nome do registro.

Quando um arquivo indexado é acesso em modo sequencial (ACCESS MODE IS SEQUENTIAL) o comando DELETE é executado sobre o último registro lido. Como estamos acessando o arquivo em modo dinâmico (ACCESS MODE IS DYNAMIC) essa leitura prévia não é necessária. Só precisamos mover o valor da chave que pretendemos excluir e executar o comando:

*----------------------------------------------------------------*
* EXCLUI REGISTRO DO CADASTRO DE CLIENTES
*----------------------------------------------------------------*
 23-EXCLUI-REGISTRO.

     MOVE CRA0200-CD-CLIENTE TO CRA0201-CD-CLIENTE
     DELETE CRA0201
     IF WT-ST-CRA0201 = "00"
        ADD 1 TO WT-CT-EXCLUIDOS
        DISPLAY "CLIENTE " CRA0200-CD-CLIENTE " EXCLUIDO"
     ELSE
        DISPLAY "*** ERRO " WT-ST-CRA0201
                " NA EXCLUSAO DO CLIENTE "
                CRA0200-CD-CLIENTE
     END-IF.

O comando DELETE também possui um formato com INVALID e NOT INVALID KEY:

DELETE arquivo
   INVALID KEY
      Bloco-de-comandos-1
   NOT INVALID KEY
      Bloco-de-comandos-2
END-DELETE

O comandos do bloco 1 serão executados se o programa não encontrar o registro cuja chave foi previamente informada, mesma situação do file status diferente de “00”. Os comandos do bloco 2 serão executados se a operação de exclusão for bem sucedida, equivalente ao file status “00”.

O parágrafo de término vai fechar os arquivos e exibir a quantidade de registros lidos, gravados, alterados e excluídos:

*----------------------------------------------------------------*
* FECHA ARQUIVOS
*----------------------------------------------------------------*
3-TERMINA.

     CLOSE CRA0200 CRA0201

     DISPLAY "LIDOS=" WT-CT-LIDOS
             " GRAVADOS=" WT-CT-GRAVADOS
             " ALTERADOS=" WT-CT-ALTERADOS
             " EXCLUIDOS=" WT-CT-EXCLUIDOS.

O tratamento do file status que fizemos em todos os parágrafo nos dá muita flexibilidade na execução desse programa. Imagine, por exemplo, que o arquivo CRA0200 tenha os seguintes registros:

I000515FARID ELETROMOVEIS                           PRACA DOUTOR GUILHERME 105                   CENTRO              ITABIRITO           MG35450000(31) 3561-1588                                                        33184516000192VAR

I000789POLICLININCA IMBUI                           AV OLIVEIRA BOTELHO 1340 SL 801              ALTO                TERESOPOLIS         RJ25600200(21) 2642-1244                          JOAO@IMBUI.COM.BR             00000000000000SRV

I000901SUPERMERCADO ABC                             AV FELICIANO SODRE 340                       VARZEA              TERESOPOLIS         RJ25540150(21) 2643-3344      (21) 2643-3345                                    03352717000121VAR

A primeira posição de cada registro (campo TP-PROCESSAMENTO) indica que queremos incluir os três registros em nosso arquivo indexado. Quando executarmos o programa pela primeira vez ele exibirá as seguintes informações na tela:

CLIENTE 000515 INCLUIDO
CLIENTE 000789 INCLUIDO
CLIENTE 000901 INCLUIDO
LIDOS=000003 GRAVADOS=000003 ALTERADOS=000000 EXCLUIDOS=000000

Mas se tentarmos executar o programa de novo, com o mesmo arquivo de entrada, ele mostrará:

*** ERRO 22 NA INCLUSAO DO CLIENTE 000515
*** ERRO 22 NA INCLUSAO DO CLIENTE 000789
*** ERRO 22 NA INCLUSAO DO CLIENTE 000901
LIDOS=000003 GRAVADOS=000000 ALTERADOS=000000 EXCLUIDOS=000000

Na segunda execução do programa os registros com chaves 515, 789 e 901 já existiam, e por isso o comando WRITE resultou num file status “22” (registro duplicado).

Esse tipo de programa é muito utilizado para atualização batch de arquivos indexados. Seu código completo ficou assim:

*================================================================*
IDENTIFICATION DIVISION.
*----------------------------------------------------------------*
PROGRAM-ID.    CRP0301.
AUTHOR.        PAULO ANDRE DIAS.
DATE-WRITTEN.  20/01/2017.
REMARKS.
*----------------------------------------------------------------*
* SISTEMA:      CR - CONTAS A RECEBER
* JOB:          03 - ATUALIZACAO CADASTRAL
* PROGRAMA:     01 - ATUALIZA CADASTRO DE CLIENTES
*
* OBJETIVO:     LER ARQUIVO SEQUENCIAL E INCLUIR OU ALTERAR RE-
*               GISTROS NO CADASTRO DE CLIENTES
*
* VERSOES:      DATA    DESCRICAO
*               ------  ---------------------------------------
*               XXXXXX  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*
*----------------------------------------------------------------*

*================================================================*
 ENVIRONMENT DIVISION.
*----------------------------------------------------------------*
 CONFIGURATION SECTION.
 SPECIAL-NAMES.
 DECIMAL-POINT IS COMMA.

 INPUT-OUTPUT SECTION.
 FILE-CONTROL.

* INTERFACE DE CLIENTES PARA ATUALIZACAO
 COPY CRS0200.

* CADASTRO DE CLIENTES
 COPY CRS0201.

*================================================================*
 DATA DIVISION.
*----------------------------------------------------------------*
 FILE SECTION.

* INTERFACE DE CLIENTES PARA ATUALIZACAO
 COPY CRF0200.

* CADASTRO DE CLIENTES
 COPY CRF0201.

*================================================================*
 WORKING-STORAGE SECTION.
*----------------------------------------------------------------*
01 WT-FILE-STATUS.
   03 WT-ST-CRA0200            PIC  X(002) VALUE SPACES.
   03 WT-ST-CRA0201            PIC  X(002) VALUE SPACES.

01 WT-CONTADORES.
   03 WT-CT-LIDOS              PIC  9(006) VALUE ZEROS.
   03 WT-CT-GRAVADOS           PIC  9(006) VALUE ZEROS.
   03 WT-CT-ALTERADOS          PIC  9(006) VALUE ZEROS.
   03 WT-CT-EXCLUIDOS          PIC  9(006) VALUE ZEROS.

*================================================================*
 PROCEDURE DIVISION.
*----------------------------------------------------------------*
 0-PRINCIPAL.

     PERFORM 1-INICIA
     PERFORM 2-PROCESSA
       UNTIL WT-ST-CRA0200 NOT = "00"
     PERFORM 3-TERMINA

     STOP RUN.

*----------------------------------------------------------------*
* ABRE ARQUIVOS E LE PRIMEIRO REGISTRO DO ARQUIVO DE ENTRADA
*----------------------------------------------------------------*
 1-INICIA.

     OPEN INPUT CRA0200
     OPEN I-O CRA0201

     READ CRA0200.

*----------------------------------------------------------------*
* SE O CLIENTE JA' EXISTIR NO CADASTRO O REGISTRO SERA' ATUALIZA-
* DO. SE NAO EXISTIR O REGISTRO SERA' INSERIDO
*----------------------------------------------------------------*
 2-PROCESSA.

     ADD 1 TO WT-CT-LIDOS

     EVALUATE CRA0200-TP-OPERACAO
         WHEN "I"
              PERFORM 21-INCLUI-REGISTRO
         WHEN "A"
              PERFORM 22-ALTERA-REGISTRO
         WHEN "E"
              PERFORM 23-EXCLUI-REGISTRO
     END-EVALUATE

     READ CRA0200.

*----------------------------------------------------------------*
* FECHA ARQUIVOS
*----------------------------------------------------------------*
 3-TERMINA.

     CLOSE CRA0200 CRA0201

     DISPLAY "LIDOS=" WT-CT-LIDOS
             " GRAVADOS=" WT-CT-GRAVADOS
             " ALTERADOS=" WT-CT-ALTERADOS
             " EXCLUIDOS=" WT-CT-EXCLUIDOS.

*----------------------------------------------------------------*
* INCLUI REGISTRO NO CADASTRO DE CLIENTES
*----------------------------------------------------------------*
 21-INCLUI-REGISTRO.

     MOVE CRA0200-CD-CLIENTE TO CRA0201-CD-CLIENTE
     MOVE CRA0200-NM-CLIENTE TO CRA0201-NM-CLIENTE
     MOVE CRA0200-NM-LOGRADOURO TO CRA0201-NM-LOGRADOURO
     MOVE CRA0200-NM-BAIRRO TO CRA0201-NM-BAIRRO
     MOVE CRA0200-NM-CIDADE TO CRA0201-NM-CIDADE
     MOVE CRA0200-CD-ESTADO TO CRA0201-CD-ESTADO
     MOVE CRA0200-CD-CEP TO CRA0201-CD-CEP
     MOVE CRA0200-NR-TELEFONE-1 TO CRA0201-NR-TELEFONE-1
     MOVE CRA0200-NR-TELEFONE-2 TO CRA0201-NR-TELEFONE-2
     MOVE CRA0200-NM-EMAIL TO CRA0201-NM-EMAIL
     MOVE CRA0200-NR-CNPJ TO CRA0201-NR-CNPJ
     MOVE CRA0200-CD-SEGMENTO TO CRA0201-CD-SEGMENTO
     WRITE CRA0201-REGISTRO
     IF WT-ST-CRA0201 = "00"
        ADD 1 TO WT-CT-GRAVADOS
        DISPLAY "CLIENTE " CRA0200-CD-CLIENTE " INCLUIDO"
     ELSE
        DISPLAY "*** ERRO " WT-ST-CRA0201
                " NA INCLUSAO DO CLIENTE "
                CRA0200-CD-CLIENTE
     END-IF.

*----------------------------------------------------------------*
* ALTERA REGISTRO NO CADASTRO DE CLIENTES
*----------------------------------------------------------------*
 22-ALTERA-REGISTRO.

     MOVE CRA0200-CD-CLIENTE TO CRA0201-CD-CLIENTE
     MOVE CRA0200-NM-CLIENTE TO CRA0201-NM-CLIENTE
     MOVE CRA0200-NM-LOGRADOURO TO CRA0201-NM-LOGRADOURO
     MOVE CRA0200-NM-BAIRRO TO CRA0201-NM-BAIRRO
     MOVE CRA0200-NM-CIDADE TO CRA0201-NM-CIDADE
     MOVE CRA0200-CD-ESTADO TO CRA0201-CD-ESTADO
     MOVE CRA0200-CD-CEP TO CRA0201-CD-CEP
     MOVE CRA0200-NR-TELEFONE-1 TO CRA0201-NR-TELEFONE-1
     MOVE CRA0200-NR-TELEFONE-2 TO CRA0201-NR-TELEFONE-2
     MOVE CRA0200-NM-EMAIL TO CRA0201-NM-EMAIL
     MOVE CRA0200-NR-CNPJ TO CRA0201-NR-CNPJ
     MOVE CRA0200-CD-SEGMENTO TO CRA0201-CD-SEGMENTO
     REWRITE CRA0201-REGISTRO
     IF WT-ST-CRA0201 = "00"
        ADD 1 TO WT-CT-GRAVADOS
        DISPLAY "CLIENTE " CRA0200-CD-CLIENTE " ALTERADO"
     ELSE
        DISPLAY "*** ERRO " WT-ST-CRA0201
                " NA ALTERACAO DO CLIENTE "
               CRA0200-CD-CLIENTE
     END-IF.

*----------------------------------------------------------------*
* EXCLUI REGISTRO DO CADASTRO DE CLIENTES
*----------------------------------------------------------------*
 23-EXCLUI-REGISTRO.

     MOVE CRA0200-CD-CLIENTE TO CRA0201-CD-CLIENTE
     DELETE CRA0201
     IF WT-ST-CRA0201 = "00"
        ADD 1 TO WT-CT-EXCLUIDOS
        DISPLAY "CLIENTE " CRA0200-CD-CLIENTE " EXCLUIDO"
     ELSE
        DISPLAY "*** ERRO " WT-ST-CRA0201
                " NA EXCLUSAO DO CLIENTE "
                CRA0200-CD-CLIENTE
     END-IF.

Lendo arquivos indexados em modo sequencial

Arquivos indexados também pode ser acessados sequencialmente, registro a registro, de forma semelhante às leituras que fizemos anteriormente com arquivos sequenciais ou sequenciais lineares.

Umas das maneiras de se fazer isso é estabelecer o modo de acesso sequencial na declaração do arquivo:

SELECT CRA0201 ASSIGN TO “$DAT/CRA0201”
    ORGANIZATION IS INDEXED
    ACCESS MODE IS SEQUENTIAL
    RECORD KEY IS CRA0201-CD-CLIENTE
    ALTERNATE RECORD KEY IS CRA0201-CD-SEGMENTO WITH DUPLICATES
    ALTERNATE RECORD KEY IS CRA0201-NR-CNPJ WITH DUPLICATES
    FILE STATUS IS WT-ST-CRA0201.

A partir daí, o arquivo é aberto na PROCEDURE (em modo INPUT ou I-O) e lido com o comando:

READ arquivo
   AT END
      Bloco-de-comandos-1
   NOT AT END
      Bloco-de-comandos-2
END-READ

Com ACCESS MODE IS SEQUENTIAL o comando READ vai ler sempre o próximo registro do arquivo, na ordem de sua chave primária, do valor mais baixo para o mais alto.

Mas muitas vezes precisamos ler sequencialmente apenas um subconjunto de registros do arquivo, normalmente posicionando a primeira leitura em algum valor específico da chave primária ou de uma das chaves alternativas. Em COBOL isso é feito com o comando START:

START arquivo KEY condição nome-da-chave

A condição após a cláusula KEY é que define em que posição do arquivo a próxima leitura acontecerá. Por exemplo, o comando abaixo estabelece que a próxima leitura do arquivo buscará o primeiro registro cujo campo CD-SEGMENTO seja igual a “VAR”.

MOVE “VAR” TO CRA0201-CD-SEGMENTO
START CRA0201 KEY EQUAL TO CRA0201-CHAVE-3

A cláusula KEY permite outras opções condicionais:

  • KEY NOT EQUAL TO (ou KEY NOT =): Posiciona a próxima leitura no primeiro registro cuja chave é diferente do valor informado
  • KEY GREATER THAN (ou KEY >): Posiciona a próxima leitura no primeiro registro cuja chave é maior do que o valor informado
  • KEY NOT LESS THAN (ou KEY NOT <): Posiciona a próxima leitura no primeiro registro cuja chave é maior ou igual ao valor informado
  • KEY GREATER THAN OR EQUAL TO (KEY >=): Igual à opção anterior

Vale reforçar que o comando START não lê o registro; ele apenas posiciona a próxima leitura sequencial num registro que atenda à condição definida. A leitura acontece no READ subsequente:

MOVE “VAR” TO CRA0201-CD-SEGMENTO
START CRA0201 KEY EQUAL TO CRA0201-CHAVE-3
READ CRA0201 NEXT

A opção NEXT pode ser omitida do comando READ se o arquivo for acessado em modo sequencial, mas deve ser incluída se o ACCESS MODE for RANDOM ou DYNAMIC.

Vamos ver a aplicação desses comandos num programa completo. Vamos aproveitar para rever também alguns recursos que apresentamos em capítulos anteriores, como o uso de tabelas internas.

O programa vai receber um código de segmento da linha de comando e gerar um relatório com todos os clientes do arquivo CRA0201 que pertencem a esse segmento. Já vimos esse arquivo em exemplos anterior. Seu book de declaração se chama CRS0201 e tem o seguinte conteúdo:

*----------------------------------------------------------------*
* CADASTRO DE CLIENTES
*----------------------------------------------------------------*
SELECT CRA0201 ASSIGN TO "$DAT/CRA0201.DAT"
   ORGANIZATION IS INDEXED
   ACCESS MODE IS DYNAMIC
   RECORD KEY IS CRA0201-CHAVE-1
   ALTERNATE RECORD KEY IS CRA0201-CHAVE-2 WITH DUPLICATES
   ALTERNATE RECORD KEY IS CRA0201-CHAVE-3 WITH DUPLICATES
   FILE STATUS IS WT-ST-CRA0201.

Seu book de detalhamento se chama CRF0201:

*----------------------------------------------------------------*
* CADASTRO DE CLIENTES
*----------------------------------------------------------------*
 FD CRA0201.
 01 CRA0201-REGISTRO.
     03 CRA0201-CHAVE-1.
        05 CRA0201-CD-CLIENTE        PIC  X(006).
     03 CRA0201-NM-CLIENTE           PIC  X(045).
     03 CRA0201-NM-LOGRADOURO        PIC  X(045).
     03 CRA0201-NM-BAIRRO            PIC  X(020).
     03 CRA0201-NM-CIDADE            PIC  X(020).
     03 CRA0201-CD-ESTADO            PIC  X(002).
     03 CRA0201-CD-CEP               PIC  X(008).
     03 CRA0201-NR-TELEFONE-1        PIC  X(020).
     03 CRA0201-NR-TELEFONE-2        PIC  X(020).
     03 CRA0201-NM-EMAIL             PIC  X(030).
     03 CRA0201-CHAVE-2.
        05 CRA0201-NR-CNPJ           PIC  9(014).
     03 CRA0201-CHAVE-3.
        05 CRA0201-CD-SEGMENTO       PIC  X(003).

O relatório mostrará apenas o código e o nome do cliente. O segmento informado na linha de comando aparecerá numa das linhas do cabeçalho. Haverá um rodapé mostrando a quantidade de clientes listados:

EMPRESA XYZ                                                       DATA: 99/99/99
FOLHA PAGTO                                                       HORA: 99:99:99
CRL0501                       CLIENTES POR SEGMENTO               PAGINA:    ZZ9
--------------------------------------------------------------------------------
SEGMENTO: XXXXXXXXXX
--------------------------------------------------------------------------------
CODIGO   CLIENTE
--------------------------------------------------------------------------------
XXXXXX   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXX   XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
--------------------------------------------------------------------------------
CLIENTES LISTADOS: ZZZ.ZZ9
--------------------------------------------------------------------------------

O usuário informará o código do segmento cujos clientes deseja listar na linha de comando. Esse código é um campo alfanumérico de três posições e é uma das chaves alternativas do arquivo. Ele pode assumir os seguintes valores:

Cobol: Tabelas internas
Figura 52. Tabela de segmentos

Usaremos uma tabela interna para obter o nome do segmento a partir do código informado via argumento. Esse nome de segmento é que aparecerá no cabeçalho do relatório.

O programa terá apenas quatro parágrafos, além do parágrafo principal. O diagrama estruturado do programa será assim:

Cobol: Diagrama estruturado
Figura 53. Diagrama estruturado do programa CRP0501

No parágrafo 1-INICIA colocaremos o comando START para posicionar o cadastro de clientes no primeiro registro cujo código de segmento seja igual ao código que foi informado como argumento na linha de comando.

O parágrafo 2-PROCESSA será executado até que todos os registros do cadastro de clientes tenham sido lidos OU que o código de segmento do cliente lido seja diferente do código informado via argumento. Nesse parágrafo faremos a impressão da linha de detalhe e chamaremos o parágrafo de impressão de cabeçalho quando a quantidade de linhas impressas for maior que o limite de linhas por página.

No parágrafo 3-TERMINA colocaremos a impressão do rodapé com a quantidade de clientes listados. Também chamaremos o parágrafo de impressão de cabeçalho se a quantidade de linhas impressas for maior que o limite de linhas por página.

No parágrafo X1-IMPRIME-CABECALHO usaremos o comando SEARCH para obter o nome de segmento associado ao código que foi informado via argumento. Já vimos a sintaxe desse comando no capítulo que falava sobre tabelas internas. O campo encontrado na tabela interna será movido para o cabeçalho.

Começamos construindo a IDENTIFICATION DIVISION de acordo com o padrão que utilizamos até agora:

*================================================================*
 IDENTIFICATION DIVISION.
*----------------------------------------------------------------*
 PROGRAM-ID.    CRP0501.
 AUTHOR.        PAULO ANDRE DIAS.
 DATE-WRITTEN.  16/01/2017.
 REMARKS.
*----------------------------------------------------------------*
* SISTEMA:      CR - CONTAS A RECEBER
* JOB:          05 - RELATORIOS
* PROGRAMA:     01 - RELACAO DE CLIENTES POR SEGMENTO
*
* OBJETIVO:     LISTAR CODIGO E NOME DE TODOS OS CLIENTES CUJO
*               SEGMENTO TENHA SIDO INFORMADO VIA ARGUMENTO
*
* VERSOES:      DATA    DESCRICAO
*               ------  ---------------------------------------
*               XXXXXX  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*
*----------------------------------------------------------------*

Declaramos o arquivo de entrada e o relatório na ENVIRONMENT e na DATA DIVISION, sem nenhuma novidade:

*================================================================*
 ENVIRONMENT DIVISION.
*----------------------------------------------------------------*
 CONFIGURATION SECTION.
 SPECIAL-NAMES.
 DECIMAL-POINT IS COMMA.

 INPUT-OUTPUT SECTION.
 FILE-CONTROL.

* SALARIOS
     COPY CRS0201.

* RELACAO DE CLIENTES POR SEGMENTO
     SELECT CRL0501 ASSIGN TO "$DAT/CRL0501.TXT"
     ORGANIZATION IS LINE SEQUENTIAL.

*================================================================*
 DATA DIVISION.
*----------------------------------------------------------------*
FILE SECTION.

* SALARIOS
    COPY CRF0201.

* RELACAO DE CLIENTES POR SEGMENTO
 FD CRL0501.
 01 CRL0501-REGISTRO             PIC  X(080).

Na WORKING, começamos com a constante que define o limite de linhas por página, com o file status do arquivo de entrada e com os contadores de páginas (que exibiremos no cabeçalho) e a quantidade de linhas impressas, que usaremos para decidir quando é a hora de imprimir um novo cabeçalho:

*================================================================*
 WORKING-STORAGE SECTION.
*----------------------------------------------------------------*
 01 WC-CONSTANTES.
    03 WC-LINHAS-POR-PAGINA     PIC  9(002) VALUE 60.

 01 WT-FILE-STATUS.
    03 WT-ST-CRA0201            PIC  X(002) VALUE SPACES.

 01 WT-CONTADORES.
    03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
    03 WT-CT-LINHAS             PIC  9(002) VALUE 99.

Nosso programa mostrará no rodapé do relatório a quantidade de clientes listados. Para isso precisamos criar um contador específico:

*================================================================*
 WORKING-STORAGE SECTION.
*----------------------------------------------------------------*
 01 WC-CONSTANTES.
     03 WC-LINHAS-POR-PAGINA     PIC  9(002) VALUE 60.

 01 WT-FILE-STATUS.
     03 WT-ST-CRA0201            PIC  X(002) VALUE SPACES.

 01 WT-CONTADORES.
     03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
     03 WT-CT-LINHAS             PIC  9(002) VALUE 99.
     03 WT-CT-CLIENTES           PIC  9(006) VALUE ZEROS.

Também precisamos criar variáveis auxiliares para formatação da data e da hora do sistema que usaremos no cabeçalho dos relatórios…

01 WT-AUXILIARES.
    03 WT-DT-SISTEMA.
       05 ANO                   PIC 9(002) VALUE ZEROS.
       05 MES                   PIC 9(002) VALUE ZEROS.
       05 DIA                   PIC 9(002) VALUE ZEROS.
    03 WT-HR-SISTEMA.
       05 HORA                  PIC 9(002) VALUE ZEROS.
       05 MINUTO                PIC 9(002) VALUE ZEROS.
       05 SEGUNDO               PIC 9(002) VALUE ZEROS.

…e a variável onde armazenaremos o código de segmento que será informado pelo usuário na linha de comando. Destacaremos essa variável num item de grupo específico, com o prefixo WA-:

01 WA-ARGUMENTOS.
    03 WA-CD-SEGMENTO           PIC X(003) VALUE SPACES.

Em seguida precisamos criar a tabela interna que associará o código ao nome de cada segmento. Será nessa tabela que buscaremos o nome que aparecerá no cabeçalho do relatório. Sua estrutura será assim:

Cobol: Estrutura de tabela interna
Figura 54. Estrutura da tabela interna de segmentos

O item de grupo SEGMENTO ocorre três vezes e é formado pelos itens elementares CD-SEGMENTO e NM-SEGMENTO. Usaremos um alfanumérico com tamanho 3 para CD-SEGMENTO e um alfanumérico com tamanho 10 para NM-SEGMENTO. Nossa tabela interna ficará assim:

01 WV-TABELA-SEGMENTOS.
    03 FILLER                   PIC X(013) VALUE
       "INDINDUSTRIA".
    03 FILLER                   PIC X(013) VALUE
       "SRVSERVICO".
    03 FILLER                   PIC X(013) VALUE
       "VARVAREJO".
01 FILLER REDEFINES WV-TABELA-SEGMENTOS.
    03 WV-SEGMENTO OCCURS 3 INDEXED BY WV-IX.
       05 WV-CD-SEGMENTO       PIC X(003).
       05 WV-NM-SEGMENTO       PIC X(010).

As quatro primeiras linhas do relatório seguem o layout padrão que usamos em exemplos anteriores; mudam apenas o nome do relatório (CRL0501) e seu título na linha 3:

01 WR-CAB1.
    03 FILLER                   PIC X(066) VALUE
       "EMPRESA XYZ".
    03 FILLER                   PIC X(006) VALUE
       "DATA: ".
    03 WR-CAB-DATA.
       05 DIA                   PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE "/".
       05 MES                   PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE "/".
       05 ANO                   PIC 9(002) VALUE ZEROS.

01 WR-CAB2.
    03 FILLER                   PIC X(066) VALUE
       "FOLHA PAGTO".
    03 FILLER                   PIC X(006) VALUE
       "HORA: ".
    03 WR-CAB-HORA.
       05 HORA                  PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE ":".
       05 MINUTO                PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE ":".
       05 SEGUNDO               PIC 9(002) VALUE ZEROS.

01 WR-CAB3.
    03 FILLER                   PIC X(030) VALUE
       "CRL0501".
    03 FILLER                   PIC X(036) VALUE
        "CLIENTES POR SEGMENTO".
    03 FILLER                   PIC X(011) VALUE
       "PAGINA: ".
    03 WR-CAB-PAGINA            PIC ZZ9 VALUE
       ZEROS.

01 WR-SEP1.
    03  FILLER                  PIC X(080) VALUE ALL "-".

Mas esse cabeçalho precisa de uma linha a mais para mostrar o nome do segmento cujo código foi informado pelo usuário. O “CAB4” terá apenas um label (“SEGMENTO: “) e uma variável para onde moveremos esse nome:

01 WR-CAB4.
    03  FILLER                  PIC X(010) VALUE "SEGMENTO: ".
    03  WR-CAB-NM-SEGMENTO      PIC X(010) VALUE SPACES.

Em seguida vem o cabeçalho com os títulos das colunas, a linha de detalhe e o rodapé onde mostraremos a quantidade de clientes listados:

01 WR-CAB5.
    03  FILLER                  PIC X(009) VALUE "CODIGO".
    03  FILLER                  PIC X(007) VALUE "CLIENTE".

01 WR-DET1.
    03  WR-DET-CD-CLIENTE       PIC X(006) VALUE SPACES.
    03  FILLER                  PIC X(003) VALUE SPACES.
    03  WR-DET-NM-CLIENTE       PIC X(045) VALUE SPACES.

01 WR-ROD1.
    03  FILLER                  PIC X(019) VALUE
        "CLIENTES LISTADOS: ".
    03  WR-ROD-CT-CLIENTES      PIC ZZZ.ZZ9 VALUE ZEROS.

Na apresentação do diagrama estruturado dissemos que o parágrafo 2-PROCESSA será executado até que não existam mais arquivos ou arquivo de entrada OU que o código de segmento do registro lido seja diferente do código informado pelo usuário. Para implementar isso, incluiremos uma condição na cláusula UNTIL do PERFORM que chama esse parágrafo:

*================================================================*
 PROCEDURE DIVISION.
*----------------------------------------------------------------*
 0-PRINCIPAL.

     PERFORM 1-INICIA
     PERFORM 2-PROCESSA
        UNTIL WT-ST-CRA0201 NOT = "00"
           OR CRA0201-CD-SEGMENTO NOT = WA-CD-SEGMENTO
     PERFORM 3-TERMINA

     STOP RUN.

No parágrafo 1-INICIA colocaremos o comando que recebe o argumento informado pelo usuário na linha de comando:

*----------------------------------------------------------------*
* OBTEM ARGUMENTO DA LINHA DE COMANDO. ABRE OS ARQUIVOS E POSI-
* CIONA O ARQUIVO DE ENTRADA NO PRIMEIRO REGISTRO CUJO CODIGO DE
* SEGMENTO SEJA IGUAL AO ARGUMENTO INFORMADO. EFETUA A PRIMEIRA
* LEITURA DO ARQUIVO DE ENTRADA.
*----------------------------------------------------------------*
 1-INICIA.

     ACCEPT WA-CD-SEGMENTO FROM COMMAND-LINE

O comando ACCEPT … FROM COMMAND-LINE traz para o programa qualquer argumento que tenha sido fornecido pelo usuário na linha de comando que chamou o programa. Por exemplo, supondo que o programa esteja sendo executado no Linux e o usuário tenha digitado…

~/bin/CRP0501 SRV

…o comando ACCEPT recuperará o argumento “SRV” e o guardará na variável indicada.

Antes de ler o primeiro registro do cadastro de clientes, usaremos o comando START para posicionar o ponteiro desse arquivo no próximo registro cujo código seja maior ou igual ao código informado pelo usuário:

OPEN INPUT CRA0201
OPEN OUTPUT CRL0501

MOVE WA-CD-SEGMENTO TO CRA0201-CD-SEGMENTO
START CRA0201 KEY NOT LESS THAN CRA0201-CHAVE-3

READ CRA0201 NEXT.

Agora vamos voltar um pouco ao conceito do comando START só para entender exatamente o que pode acontecer no momento desse primeiro READ. Suponha que o cadastro de clientes tenha o seguinte conteúdo e que o usuário tenha informado o código “SRV” na linha de comando:

Cobol: Posicionamento de ponteiro
Figura 55. Posicionamento do ponteiro para segmento maior ou igual a “SRV”

Depois de executar o comando START o programa procura na área de índices o primeiro registro que tenha “SRV” como valor da chave. O próximo READ, portanto, descobriria que esse registro está na posição 7 e recuperaria os dados que estivessem nessa posição.

Agora imagine que o usuário tenha preenchido o argumento com “TTT”. Nesse caso, o comando START posicionaria o ponteiro no próximo registro cujo campo CD-SEGMENTO seja maior ou igual a “TTT”:

Cobol: Posicionamento de monteiro
Figura 56. Posicionamento de ponteiro para segmento maior ou igual a “TTT”

No nosso exemplo, não existe nenhum registro associado ao valor “TTT”. O primeiro segmento maior ou igual a “TTT” é o “VAR”, que aponta para o registro 1, e o próximo comando READ vai recuperar os campos desse registro. O parágrafo 2-PROCESSA deve ser executado até o fim do arquivo OU que código de segmento seja diferente do segmento informado. Como a primeira leitura já trouxe um registro com código diferente, nada será impresso no relatório.

Vejamos outra possibilidade: o usuário informa “ZZZ” como código de segmento:

Cobol: Posicionamento de ponteiro
Figura 57. Posicionamento de ponteiro para segmento maior ou igual a “ZZZ”

Não existe registro com segmento maior ou igual a “ZZZ” e o ponteiro do arquivo será posicionado depois do último registro. O próximo comando READ vai retornar file status igual a “10”. Mais uma vez, o parágrafo 2-PROCESSA não será executado pois a primeira leitura já provocou uma situação semelhante a fim de arquivo.

Esse é o comportamento que se espera do programa. Esses exemplos procuraram mostrar que o START com a condição NOT LESS THAN (maior ou igual) é aplicável à maioria das situações em que precisamos ler um subconjunto de registros de um arquivo de entrada, sem nos preocuparmos com tratamentos de INVALID KEYs ou IFs adicionais.

O parágrafo 2-PROCESSA precisa apenas verificar se o limite de linhas de página foi atingido, imprimir a linha detalhe e ler o próximo registro do arquivo de entrada. Observe que é aqui que incrementaremos o contador de clientes listados:

*----------------------------------------------------------------*
* IMPRIME TODOS OS CLIENTES SELECIONADOS
*----------------------------------------------------------------*
 2-PROCESSA.

     IF WT-CT-LINHAS > WC-LINHAS-POR-PAGINA
        PERFORM X1-IMPRIME-CABECALHO
     END-IF

     MOVE CRA0201-CD-CLIENTE TO WR-DET-CD-CLIENTE
     MOVE CRA0201-NM-CLIENTE TO WR-DET-NM-CLIENTE
     WRITE CRL0501-REGISTRO FROM WR-DET1
     ADD 1 TO WT-CT-LINHAS
     ADD 1 TO WT-CT-CLIENTES

     READ CRA0201 NEXT.

E como o relatório tem um rodapé que só vai aparecer no final, podemos codificar sua impressão no próprio parágrafo 3-TERMINA:

*----------------------------------------------------------------*
* IMPRIME RODAPE E FECHA ARQUIVOS
*----------------------------------------------------------------*
 3-TERMINA.

     IF WT-CT-LINHAS > WC-LINHAS-POR-PAGINA
        PERFORM X1-IMPRIME-CABECALHO
     END-IF

     MOVE WT-CT-CLIENTES TO WR-ROD-CT-CLIENTES
     WRITE CRL0501-REGISTRO FROM WR-SEP1
     WRITE CRL0501-REGISTRO FROM WR-ROD1
     WRITE CRL0501-REGISTRO FROM WR-SEP1

     CLOSE CRA0201 CRL0501.

O último parágrafo do programa é aquele que imprime as linhas de cabeçalho. A diferença em relação a exemplos que vimos anteriormente é que, aqui, teremos que procurar o nome do segmento na tabela interna. Faremos isso usando um dos formatos do comando SEARCH:

*----------------------------------------------------------------*
* IMPRIME CABECALHO
*----------------------------------------------------------------*
 X1-IMPRIME-CABECALHO.

     ACCEPT WT-DT-SISTEMA FROM DATE
     ACCEPT WT-HR-SISTEMA FROM TIME
     ADD 1 TO WT-CT-PAGINA

     MOVE CORR WT-DT-SISTEMA TO WR-CAB-DATA
     MOVE CORR WT-HR-SISTEMA TO WR-CAB-HORA
     MOVE WT-CT-PAGINA TO WR-CAB-PAGINA

     SEARCH WV-SEGMENTOS VARYING WV-IX
       WHEN WV-CD-SEGMENTO(WV-IX) = WA-CD-SEGMENTO
            MOVE WV-NM-SEGMENTO(WV-IX) TO WR-CAB-NM-SEGMENTO
     END-SEARCH

     WRITE CRL0501-REGISTRO FROM WR-CAB1 AFTER PAGE
     WRITE CRL0501-REGISTRO FROM WR-CAB2
     WRITE CRL0501-REGISTRO FROM WR-CAB3
     WRITE CRL0501-REGISTRO FROM WR-SEP1
     WRITE CRL0501-REGISTRO FROM WR-CAB4
     WRITE CRL0501-REGISTRO FROM WR-SEP1
     WRITE CRL0501-REGISTRO FROM WR-CAB5
     WRITE CRL0501-REGISTRO FROM WR-SEP1

     MOVE 8 TO WT-CT-LINHAS.

O comando SEARCH … VARYING é aplicado sobre o item de grupo WV-SEGMENTOS, que é quem foi declarado com a cláusula OCCURS. Ele é formado por dois itens elementares (WV-CD-SEGMENTO e WV-NM-SEGMENTO). Quando o SEARCH encontra um código de segmento igual ao código do argumento, o próprio comando move o nome correspondente para o cabeçalho.

Testando esse programa para o segmento “VAR” geramos o seguinte relatório:

EMPRESA XYZ                                                       DATA: 21/01/17
FOLHA PAGTO                                                       HORA: 09:03:55
CRL0501                       CLIENTES POR SEGMENTO               PAGINA:      1
--------------------------------------------------------------------------------
SEGMENTO: VAREJO
--------------------------------------------------------------------------------
CODIGO   CLIENTE
--------------------------------------------------------------------------------
000515   FARID ELETROMOVEIS
000901   SUPERMERCADO ABC
000988   PAPELARIA OURO PRETO
001101   SUPERMERCADO ITAMARKET
002005   CASA COLORIDA MOVEIS
002201   TEREPOINT PECAS E AUTOPECAS
--------------------------------------------------------------------------------
CLIENTES LISTADOS:       6
--------------------------------------------------------------------------------

Observe agora o que seria gerado se informássemos “TTT” ou “ZZZ” na linha de comando:

EMPRESA XYZ                                                       DATA: 24/01/17
FOLHA PAGTO                                                       HORA: 07:29:34
CRL0501                       CLIENTES POR SEGMENTO               PAGINA:      1
--------------------------------------------------------------------------------
SEGMENTO:
--------------------------------------------------------------------------------
CODIGO   CLIENTE
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
CLIENTES LISTADOS:       0
--------------------------------------------------------------------------------

Procure acompanhar o programa, comando a comando, para verificar exatamente em que momento e em que condições cada uma das linhas acima foi impressa. O programa completo segue abaixo:

*================================================================*
 IDENTIFICATION DIVISION.
*----------------------------------------------------------------*
 PROGRAM-ID.    CRP0501.
 AUTHOR.        PAULO ANDRE DIAS.
 DATE-WRITTEN.  16/01/2017.
 REMARKS.
*----------------------------------------------------------------*
* SISTEMA:      CR - CONTAS A RECEBER
* JOB:          05 - RELATORIOS
* PROGRAMA:     01 - RELACAO DE CLIENTES POR SEGMENTO
*
* OBJETIVO:     LISTAR CODIGO E NOME DE TODOS OS CLIENTES CUJO
*               SEGMENTO TENHA SIDO INFORMADO VIA ARGUMENTO
*
* VERSOES:      DATA    DESCRICAO
*               ------  ---------------------------------------
*               XXXXXX  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*
*----------------------------------------------------------------*

*================================================================*
 ENVIRONMENT DIVISION.
*----------------------------------------------------------------*
 CONFIGURATION SECTION.
 SPECIAL-NAMES.
 DECIMAL-POINT IS COMMA.

 INPUT-OUTPUT SECTION.
 FILE-CONTROL.

* SALARIOS
    COPY CRS0201.

* RELACAO DE CLIENTES POR SEGMENTO
    SELECT CRL0501 ASSIGN TO "$DAT/CRL0501.TXT"
    ORGANIZATION IS LINE SEQUENTIAL.

*================================================================*
 DATA DIVISION.
*----------------------------------------------------------------*
FILE SECTION.

* SALARIOS
 COPY CRF0201.

* RELACAO DE CLIENTES POR SEGMENTO
 FD CRL0501.
 01 CRL0501-REGISTRO             PIC  X(080).

*================================================================*
 WORKING-STORAGE SECTION.
*----------------------------------------------------------------*
01 WC-CONSTANTES.
    03 WC-LINHAS-POR-PAGINA     PIC  9(002) VALUE 60.

01 WT-FILE-STATUS.
    03 WT-ST-CRA0201            PIC  X(002) VALUE SPACES.

01 WT-CONTADORES.
    03 WT-CT-PAGINA             PIC  9(003) VALUE ZEROS.
    03 WT-CT-LINHAS             PIC  9(002) VALUE 99.
    03 WT-CT-CLIENTES           PIC  9(006) VALUE ZEROS.

01 WT-AUXILIARES.
    03 WT-DT-SISTEMA.
       05 ANO                   PIC 9(002) VALUE ZEROS.
       05 MES                   PIC 9(002) VALUE ZEROS.
       05 DIA                   PIC 9(002) VALUE ZEROS.
    03 WT-HR-SISTEMA.
       05 HORA                  PIC 9(002) VALUE ZEROS.
       05 MINUTO                PIC 9(002) VALUE ZEROS.
       05 SEGUNDO               PIC 9(002) VALUE ZEROS.

01 WA-ARGUMENTOS.
    03 WA-CD-SEGMENTO           PIC X(003) VALUE SPACES.

01 WV-TABELA-SEGMENTOS.
    03 FILLER                   PIC X(013) VALUE
       "INDINDUSTRIA".
    03 FILLER                   PIC X(013) VALUE
       "SRVSERVICO".
    03 FILLER                   PIC X(013) VALUE
       "VARVAREJO".
01 FILLER REDEFINES WV-TABELA-SEGMENTOS.
    03 WV-SEGMENTOS OCCURS 3 INDEXED BY WV-IX.
       05 WV-CD-SEGMENTO       PIC X(003).
       05 WV-NM-SEGMENTO       PIC X(010).

01 WR-CAB1.
    03 FILLER                   PIC X(066) VALUE
       "EMPRESA XYZ".
    03 FILLER                   PIC X(006) VALUE
       "DATA: ".
    03 WR-CAB-DATA.
       05 DIA                   PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE "/".
       05 MES                   PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE "/".
       05 ANO                   PIC 9(002) VALUE ZEROS.

01 WR-CAB2.
    03 FILLER                   PIC X(066) VALUE
       "FOLHA PAGTO".
    03 FILLER                   PIC X(006) VALUE
       "HORA: ".
    03 WR-CAB-HORA.
       05 HORA                  PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE ":".
       05 MINUTO                PIC 9(002) VALUE ZEROS.
       05 FILLER                PIC X(001) VALUE ":".
       05 SEGUNDO               PIC 9(002) VALUE ZEROS.

01 WR-CAB3.
    03 FILLER                   PIC X(030) VALUE
       "CRL0501".
    03 FILLER                   PIC X(036) VALUE
       "CLIENTES POR SEGMENTO".
    03 FILLER                   PIC X(011) VALUE
       "PAGINA: ".
    03 WR-CAB-PAGINA            PIC ZZ9 VALUE
       ZEROS.

01 WR-SEP1.
    03  FILLER                  PIC X(080) VALUE ALL "-".

01 WR-CAB4.
    03  FILLER                  PIC X(010) VALUE "SEGMENTO: ".
    03  WR-CAB-NM-SEGMENTO      PIC X(010) VALUE SPACES.

01 WR-CAB5.
    03  FILLER                  PIC X(009) VALUE "CODIGO".
    03  FILLER                  PIC X(007) VALUE "CLIENTE".

01 WR-DET1.
    03  WR-DET-CD-CLIENTE       PIC X(006) VALUE SPACES.
    03  FILLER                  PIC X(003) VALUE SPACES.
    03  WR-DET-NM-CLIENTE       PIC X(045) VALUE SPACES.

01 WR-ROD1.
    03  FILLER                  PIC X(019) VALUE
        "CLIENTES LISTADOS: ".
    03  WR-ROD-CT-CLIENTES      PIC ZZZ.ZZ9 VALUE ZEROS.

*================================================================*
 PROCEDURE DIVISION.
*----------------------------------------------------------------*
 0-PRINCIPAL.

     PERFORM 1-INICIA
     PERFORM 2-PROCESSA
       UNTIL WT-ST-CRA0201 NOT = "00"
          OR CRA0201-CD-SEGMENTO NOT = WA-CD-SEGMENTO
     PERFORM 3-TERMINA

     STOP RUN.

*----------------------------------------------------------------*
* OBTEM ARGUMENTO DA LINHA DE COMANDO. ABRE OS ARQUIVOS E POSI-
* CIONA O ARQUIVO DE ENTRADA NO PRIMEIRO REGISTRO CUJO CODIGO DE
* SEGMENTO SEJA IGUAL AO ARGUMENTO INFORMADO. EFETUA A PRIMEIRA
* LEITURA DO ARQUIVO DE ENTRADA.
*----------------------------------------------------------------*
 1-INICIA.

     ACCEPT WA-CD-SEGMENTO FROM COMMAND-LINE

     OPEN INPUT CRA0201
     OPEN OUTPUT CRL0501

     MOVE WA-CD-SEGMENTO TO CRA0201-CD-SEGMENTO
     START CRA0201 KEY NOT LESS THAN CRA0201-CHAVE-3
     READ CRA0201 NEXT.

*----------------------------------------------------------------*
* IMPRIME TODOS OS CLIENTES SELECIONADOS
*----------------------------------------------------------------*
 2-PROCESSA.

     IF WT-CT-LINHAS > WC-LINHAS-POR-PAGINA
        PERFORM X1-IMPRIME-CABECALHO
     END-IF

     MOVE CRA0201-CD-CLIENTE TO WR-DET-CD-CLIENTE
     MOVE CRA0201-NM-CLIENTE TO WR-DET-NM-CLIENTE
     WRITE CRL0501-REGISTRO FROM WR-DET1
     ADD 1 TO WT-CT-LINHAS
     ADD 1 TO WT-CT-CLIENTES

     READ CRA0201 NEXT.

*----------------------------------------------------------------*
* IMPRIME RODAPE E FECHA ARQUIVOS
*----------------------------------------------------------------*
 3-TERMINA.

     IF WT-CT-LINHAS > WC-LINHAS-POR-PAGINA
        PERFORM X1-IMPRIME-CABECALHO
     END-IF

     MOVE WT-CT-CLIENTES TO WR-ROD-CT-CLIENTES
     WRITE CRL0501-REGISTRO FROM WR-SEP1
     WRITE CRL0501-REGISTRO FROM WR-ROD1
     WRITE CRL0501-REGISTRO FROM WR-SEP1

     CLOSE CRA0201 CRL0501.

*----------------------------------------------------------------*
* IMPRIME CABECALHO
*----------------------------------------------------------------*
 X1-IMPRIME-CABECALHO.

     ACCEPT WT-DT-SISTEMA FROM DATE
     ACCEPT WT-HR-SISTEMA FROM TIME
     ADD 1 TO WT-CT-PAGINA

     MOVE CORR WT-DT-SISTEMA TO WR-CAB-DATA
     MOVE CORR WT-HR-SISTEMA TO WR-CAB-HORA
     MOVE WT-CT-PAGINA TO WR-CAB-PAGINA

     SEARCH WV-SEGMENTOS VARYING WV-IX
       WHEN WV-CD-SEGMENTO(WV-IX) = WA-CD-SEGMENTO
            MOVE WV-NM-SEGMENTO(WV-IX) TO WR-CAB-NM-SEGMENTO
     END-SEARCH

     WRITE CRL0501-REGISTRO FROM WR-CAB1 AFTER PAGE
     WRITE CRL0501-REGISTRO FROM WR-CAB2
     WRITE CRL0501-REGISTRO FROM WR-CAB3
     WRITE CRL0501-REGISTRO FROM WR-SEP1
     WRITE CRL0501-REGISTRO FROM WR-CAB4
     WRITE CRL0501-REGISTRO FROM WR-SEP1
     WRITE CRL0501-REGISTRO FROM WR-CAB5
     WRITE CRL0501-REGISTRO FROM WR-SEP1

     MOVE 8 TO WT-CT-LINHAS.

Anterior Conteúdo Próxima