Página 1 de 1

#xcommand

Enviado: 09 Fev 2008 15:39
por hrodrigom
Boa tarde companheiros,

Existe alguma forma de declarar um #xcommand em uma função, e que outras funções chamadas a partir desta reconheçãm este comando?

exemplo:

Código: Selecionar todos

function teste()
   #xcommand alert <var> => alert()
   teste2()
return

function teste2()
   alert 'rodrigo'
return
Bom fim de semana a todos

Enviado: 09 Fev 2008 17:40
por Maligno
#xcommand é um comando de pré-compilação. Logo, para se tornar acessível a outros arquivos, você só tem duas opções: replicar o comando em cada arquivo (horrível) ou embutir o comando num arquivo de cabeçalho e informá-lo em cada arquivo em que o comando for utilizado. A última alternativa, claro, é o método "canônico". Todos fazem assim.

Enviado: 10 Fev 2008 00:11
por rochinha
Amiguinho

Como o Maligno postou, algo assim:

Teste.ch

Código: Selecionar todos

#xcommand alert <var> => alert() 
Codigo.prg

Código: Selecionar todos

#include "teste.ch"

function teste() 
   teste2() 
return 

function teste2() 
   alert 'rodrigo' 
return

Enviado: 13 Fev 2008 20:24
por hrodrigom
Na verdade, eu coloquei o alert a modo de exemplo.

o que eu quero mesmo é aproveitar meus relatorios no formato
@ xx, yy say 'texto'
e geralos em pdf..
ja está tudo pronto..
so que eu tenho que ir alterando prg por prg e colocar um #xcommand antes do relatorio.. e ainda, deve respeitar uma condição, se for para imprimir normal na impressora, ignora-se este # comando.

Pensei que fosse existir alguma maneira de se fazer isto dentro de uma função. e chamar esta função sempre no inicio de cada relatorio..

Enviado: 13 Fev 2008 21:22
por Maligno
Pra falar a verdade, não entendi muito bem o que você quer. Mas em se tratando de analisar uma certa condição antes da impressão, você pode muito bem fazer o teste dessa condição num #xcommand mais elaborado e informar nos fontes apenas o #include necessário. Claro que a cada mudança de comando, deve-se recompilar tudo. :)

Enviado: 13 Fev 2008 21:22
por rochinha
Amiguinho

Não sei como funciona suas funções de impressão via PDF, mas tente implementar um IF.ELSE.ENDIF dentro do XCommand @..SAY e SET PRINTER dentro do .CH que contenha estes.

Já cheguei a fazer isto também mas foi a long time ago

O que eu fiz, peguei o STD.CH do Clipper, copiei para outro arquivo MEUSTD.CH os comandos que eu ia modificar, fiz as alterações e dentro do meu .PRG que precisava daquela caracteristica eu apenas comandava:

#include "MEUSTD.CH"

Veja um exemplo do que fiz com o comando USE transformando-o em OPEN onde passo somente o nome do .DBF e ele abre sozinho o .CDX, pois so uso um por .DBF:

Código: Selecionar todos

#command OPEN <(db)>                                                    ;
             [VIA <rdd>]                                                ;
             [ALIAS <a>]                                                ;
             [<new: NEW>]                                               ;
             [<ex: EXCLUSIVE>]                                          ;
             [<sh: SHARED>]                                             ;
             [<ro: READONLY>]                                           ;
             [INDEX <(index1)> [, <(indexn)>]]                          ;
       => iif( Select( <(db)> )==0, iif( !File( <(db)>+".CDX" ), ( Alert( "Arquivo "+<(db)>+" esta sem indices. Abrindo sem indices. Reorganiza primeiro" ), dbNetUseArea( <.new.>, <rdd>, <(db)>, <(a)>, if(<.sh.> .or. <.ex.>, !<.ex.>, NIL), <.ro.>, 0 ) ), ( dbNetUseArea( <.new.>, <rdd>, <(db)>, <(a)>, if(<.sh.> .or. <.ex.>, !<.ex.>, NIL), <.ro.>, 0 ), dbSetIndex( <(db)> ) ) ), ( dbSelectArea( <(db)> ) ) )

Enviado: 13 Fev 2008 21:36
por Maligno
No seu caso, Rochinha, uma dica pra evitar o trabalho de ter que mencionar seu header em todos os fontes: mencioná-lo no próprio STD.CH. Uma vez que o STD.SH é default no Clipper e não precisa ser informado nos fontes, basta inserir nele algo do tipo:

Código: Selecionar todos

#ifndef   MEUSTD_CH
#define   MEUSTD_CH
#include "MEUSTD.CH"
#endif
Se você não mais utiliza esse esquema, deixo como dica para os demais companheiros.

Enviado: 13 Fev 2008 22:43
por ederxc
Puotz , cabe terraquios na conversa ???

Enviado: 14 Fev 2008 10:26
por rochinha
Amiguinhos,

Maligno: Eu ainda uso esta técnica, mas mantenho intacto os originais por via de duvidas e sempre carrego os .CH no cabecalho para saber o que estou vinculando ao codigo. Como uso Fivewin o mesmo exige esta caracteristica.

EderXC: Com este nick voce já é um ET.

HRodrigom: No topico que disponibilizei neste link eu exemplifico uma forma de dar uma pequena modificada nos comandos @..SAY no momento da impressão. Lógico que não é um código para se usar como Clipper, mas voce pode usar o conteudo como base, pois o mesmo não usa nada mais que o motor de baixo nivel do Clipper para escrever o conteudo do arquivo de impressão.

Mas ali o autor nos ajudou a usar este recurso sem sair do @..SAY facilitando nossa codificação.

Outros recursos destes arquivos .CH foram explorados em vários utilitários por ai afora.

O pequeno trecho abaixo nos auxiliava a salvar e recuperar o conteudo de GETs, muito util quando tinhamos muitos GET na tela e necessitavamos PAGINA-los, ou seja uma tela de cadastro com 50 GETs e somente 30 cabiam na primeira tela e o restante numa segunda. A facilidade permitia que fosse salvos o conteudo dos GET a medida que pulavamos de pagina em pagina, uma técnica muito usada nos aplicativos feitos com MIRO.

Código: Selecionar todos

#command SAVE GET TO <var>      => PUBLIC <var> := M->GetList; M->GetList := {}
#command RESTORE GET FROM <var> => M->GetList := <var>
Neste conjunto eu modifiquei os comandos habituais de controle de registros de forma a gravar um LOG de utilização a pedido de um cliente que queria em duas horas que eu gravasse todos os acontecimentos de modificações de registros em meu sistema para capturar algum expertinho.

O jeito foi inxertar algumas funções nos comandos ja existentes e recompilar meu aplicativo.

Código: Selecionar todos

#command APPEND BLANK           => dbNetAppend( 0 ) ; dbCommitLog('I', PROCNAME() )
#command APPEND BLANK <n>       => dbNetAppend( <n> )
#command APPEND TO <(file)>     => AppendToFile( <(file)> )
#command APPEND REG FROM <(file)>     => AppendFromFile( <(file)> )
#command PACK                   => __dbPack() ; dbCommitLog('E', PROCNAME())
#command ZAP                    => __dbZap()  ; dbCommitLog('E', PROCNAME())
#command COMMIT                 => dbUnlock() ; dbCommitAll() 
#command SKIP 0                 => dbUnlock() ; dbCommitAll() 
#command REGLOCK                => dbNetRegLock( 0 )    ; dbCommitLog('M', PROCNAME())
#command REGLOCK <n>            => dbNetRegLock( <n> )  ; dbCommitLog('M', PROCNAME())
#command FILELOCK               => dbNetFileLock( 0 )   ; dbCommitLog('M', PROCNAME())
#command FILELOCK <n>           => dbNetFileLock( <n> ) ; dbCommitLog('M', PROCNAME())
#command DELETE => dbNetRegLock(0)                                      ;
         ;         dbDelete() ; dbCommitLog('E', PROCNAME())
A função dbCommitLOG() gravava as informações em um .DBF que era visualizado pelo cliente a qualquer momento, podendo ele filtrar por usuario, data e hora e saber qual foi o tipo de movimento que os registro sofreram dentro de um determinado modulo.

Código: Selecionar todos

FUNCTION dbCommitLog( LOG_TIPO )
#ifdef LOG_USER // Habilito se for decidido usar auditoria de usuario 
    LOG_AREA := SELECT()
    USE NF.LOG NEW ALIAS NFLOG
    dbNetAppend( 0 )
    NFLOG->IDLOG   := RECCO()+1
    NFLOG->DATA    := DATE()
    NFLOG->HORA    := TIME()
    NFLOG->USUARIO := M->USUARIO
    IF     LOG_TIPO = 'I'
           NFLOG->ACAO    := 'INCLUSAO'
    ELSEIF LOG_TIPO = 'E'
           NFLOG->ACAO    := 'EXCLUSAO'
    ELSEIF LOG_TIPO = 'M'
           NFLOG->ACAO    := 'MANUTENCAO'
    ENDIF
    NFLOG->MODULO  := PROCNAME()
    dbUnlock()
    dbCommitAll()
    USE
    SELECT( LOG_AREA )
#endif
RETURN .T.
Depois quando passei a usar SubNTX em meus aplicativos a codificação aumentou em até 4 linhas para cada filtragem então resolvi dinamizar minha forma de programar para não perder muito tempo e ir me familiarizando com os comandos do mundo CDX que eu passaria a usar logo depois com Clipper 5.3, pois com Clipper 5.2 dava uns paus insanos.

A mudança foi simples pois usava muito o comando SET FILTER e para usa-lo com o novo esquema foi so acrescentar o parametro SCOPED e pronto:

Código: Selecionar todos

#ifdef CDX
       #command SET FILTER TO <x> SCOPED                                  ;
        => if ( Empty(<(x)>) )                                            ;
         ;    Sx_ClrScope( 0 )                                            ;
         ;    Sx_ClrScope( 1 )                                            ;
         ; else                                                           ;
         ;    Sx_SetScope( 0, <x> )                                       ;
         ;    Sx_SetScope( 1, <x> )                                       ;
         ; end
       #command SET SUBFILTER TO <x> [ON ORDER <SubOrder>]                ;
        => ordSetFocus( <SubOrder> )                                      ;
         ; Sx_SetScope( 0, <x> )                                          ;
         ; Sx_SetScope( 1, <x> )
#else
       #command SET SUBFILTER TO <xpr> [TAG <SubIndex>] =>     ;
         M->SUBARQ := substr(ordName(),1,2)+substr(strtran(time(),":",""),4,3)+".NTX"  ;;
         SubNtx( ordBagName(), M->SUBARQ, <xpr> )   ;;
         ordListClear() ; ordListAdd( M->SUBARQ )   ;;
         ordSetFocus( NDXCOUNT() )
       #command SET SUBFILTER TO <xpr> [ON ORDER <SubOrder>] =>     ;
         ordSetFocus( <SubOrder> )                  ;;
         M->SUBARQ := '_'+substr(ordName(),1,2)+substr(strtran(time(),":",""),4,3)+".NTX"  ;;
         SubNtx( ordBagName(), M->SUBARQ, <xpr> )   ;;
         ordListClear() ; ordListAdd( M->SUBARQ )   ;;
         ordSetFocus( M->SUBARQ )
       #command SUBINDEX ON <xpr> TO <SubIndex> [TAG <Index>] =>     ;
         SubNtx( ordBagName(), <"SubIndex">+".NTX", <xpr> )   

#endif

#command DELETE TAGS => F_Erase( "SUB*.NTX" )

#command ADD INDEX <SubIndex> => ordListAdd( <"SubIndex"> ) ;;
                                 ordSetFocus( NDXCOUNT() )

#command RESET ORDER <order> => ordListReset( <order> )

As funçoes acima estão aqui:

Código: Selecionar todos

FUNCTION F_ERASE( ARQUIVOS )
   CONTADOR  := ADIR( ARQUIVOS )
   IF CONTADOR != 0
      DECLARE TXT_NOMES[ CONTADOR ]
      ADIR( ARQUIVOS, TXT_NOMES )
      FOR CONTADOR := 1 TO LEN( TXT_NOMES )
          FERASE( TXT_NOMES[CONTADOR] )
      NEXT
   ENDIF
   RETURN .T.

FUNCTION NDXCOUNT()
   LOCAL counter
   FOR counter = 1 TO 15
       IF EMPTY(INDEXKEY(counter))
          EXIT
       ENDIF
   NEXT
   RETURN (counter-1)

FUNCTION ordList()
   LOCAL counter
   PUBLIC nomes_ndx := {}
   FOR counter = 1 TO 15
       IF EMPTY(INDEXKEY(counter))
          EXIT
       ENDIF
       AADD(nomes_ndx,ORDNAME(counter))
   NEXT
   RETURN nomes_ndx

FUNCTION ordListReset( ord_number )
   LOCAL counter, nomes_ndx := ordList()
   if valtype(ord_number) = 'C'
      ord_number := ordSetList( ord_number )
   endif
   ordListClear()
   FOR counter = 1 TO len(nomes_ndx)
       IF counter = ord_number
       ELSE
          ordListAdd(nomes_ndx[counter])
       ENDIF
   NEXT
   RETURN .t.

FUNCTION ordSetList( O_R_DEM )
   FOR counter = 1 TO 15
       ordSFocus := counter
       IF EMPTY(INDEXKEY(counter))
          EXIT
       ENDIF
       IF UPPER(ALLTRIM(ORDNAME(counter))) = UPPER(ALLTRIM(O_R_DEM))
          EXIT
       ENDIF
   NEXT
   RETURN ordSFocus
Fugi de forma gigantesca do conteudo do topico pois me empolguei mas pelo menos os colegas saberão que é possivel implementar e dinamizar o uso do Clipper.

Lembro me até que cheguei a compilar codigo puramente Cobol com Clipper, usando um .CH que continha uma série de xCommands que simulavam toda hierarquia Cobol, mas infelizmente, perdi o arquivo e até hoje ainda procuro, só pra matar saudades.