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.