Funções para o tratamento de arquivos INI

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Funções para o tratamento de arquivos INI

Mensagem por Maligno »

Conforme havia dito anteriormente (nem poderia ter sido posteriormente :), seguem abaixo as funções que fiz para manipulação de arquivos INI.
A idéia inicial era tratar mais facilmente os arquivos de retorno do ACBrNFeMonitor, mas elas podem ser utilizadas para quaisquer outros arquivos INI, inclusive o de configuração do ACBrNFe. A função principal é a ExtractINI(), que lê e organiza os dados do INI em uma matriz, mais facilmente manipulável. Como contrapartida, temos a função BuildINI(), que constrói um INI a partir de uma matriz de configuração.

Apenas atentem para o detalhe: ExtractINI() retorna uma matriz com 4 elementos. Os elementos 1, 2 e 4 são mais ligados ao ACBrNFeMonitor. Mas, qualquer INI pode ser extraído para a matriz. A diferença é que esses elementos poderão não conter coisa alguma. Nesse caso, o elemento 3 armazenará o conteúdo do INI. E as demais funções não usam esses 4 elementos. Eles usam apenas a estrutura que contém o elemento 3. Ou seja, essas funções são mais genéricas.

O código fonte:

Código: Selecionar todos

#include "inifile.ch"


#define _EOL      Chr(13)+Chr(10)
#define _EOL_SIZE 2
#define _TRUE     .t.
#define _FALSE    .f.


// *************************************************************************************************
// A matriz de retorno desta função não está ligada à configuração do ACBrNFeMonitor mas as demais
// funções de manipulação de INI não tem essa ligação. Ou seja, aINI[3] (configuração) e aINI[4]
// (NFe) devem ser informadas isoladamente para essas funções de apoio. Ademais, essa funções podem
// ser utilizadas em qualquer arquivo INI que não tenha vínculo com a estrutura do ACBrNFeMonitor.
// *************************************************************************************************
function ExtractINI(cContent) // O conteúdo inteiro do INI que, normalmente, é um arquivo pequeno.
local cSection                // 
local nCol1                   // 
local nCol2                   // 
local cSymb                   // 
local aItem                   //
local i1                      //
local i2                      //
local lNFe := FALSE           // se TRUE, está lendo dados de uma NFe.
local aINI := {0,"",{},{}}    // Elementos: 1=se for o número 0, indicará sucesso na leitura
                              //                     Obs: havendo erro, será devolvido o valor -1
                              //            2=texto encontrado antes da primeira seção ("", se não existir)
                              //            3=matriz de seções, que conterá matrizes com dois elementos:
                              //                     1=nome da seção
                              //                     2=matriz de propriedades, que conterá dois elementos:
                              //                                 1=nome da propriedade
                              //                                 2=conteúdo
                              //            4=matriz de NFes, conterá matrizes com dois elementos:
                              //                     1=número da NFe (texto, sem o prefixo "NFE")
                              //                     2=matriz de propriedades da NFe, com dois elementos:
                              //                                 1=nome da propriedade
                              //                                 2=conteúdo

// Alguns INIs terminam sem um par CR/LF. Fica mais fácil analisar se ele existir.
cContent += _EOL

// Se o INI contiver algum texto antes de qualquer símbolo, ele será copiado
// integralmente para o segundo elemento da matriz de retorno. Um caso assim
// ocorre no arquivo de retorno do ACBrNFeMonitor.
if (nCol1 := At("[",cContent)) = 0
   // Se não for um INI válido, não há o que fazer.
   return {-1,cContent} // retorna apenas dois elementos: o erro no primeiro e o próprio conteúdo no segundo
end

// Pode haver um texto antes da primeira seção.
if nCol1 > 1
   nCol2 := At(_EOL,cContent)
   nCol2 := if(nCol2=0, nCol1-1, nCol2-1)
   aINI[_INI_TEXT] := SubStr(cContent,1,nCol2)
end

// Cada linha será tratada individualmente, começando pela primeira seção.
// Serão armazenados todos os pares (XXX=YYY) em sub-matrizes dentro da
// seção atualmente aberta. A variável "nCol1" vai percorrer as linhas,
// sempre parando no primeiro caractere de cada uma, para a próxima iteração.
while TRUE
   // Separar a linha, já suprimindo o par CR/LF (dois inúteis).
   nCol2 := At(_EOL,SubStr(cContent,nCol1))+nCol1-1
   cLine := AllTrim(SubStr(cContent,nCol1,nCol2-nCol1))
   nCol1 := nCol2+_EOL_SIZE

   if Left(cLine,1) = "["
      nCol2 := At("]",cLine)
      cSymb := AllTrim(SubStr(cLine,2,nCol2-2))
      *
      if (lNFe := Left(cSymb,3) = "NFE")
         AAdd(aINI[_INI_NFES],{SubStr(cSymb,4),{}})
      else
         AAdd(aINI[_INI_SECTIONS],{cSymb,{}})
      end
   else
      // Se o operador de atribuição não for encontrado, a linha será ignorada por completo.
      if (nCol2 := At("=",cLine)) > 0
         aItem := {AllTrim(Left(cLine,nCol2-1)),StrTran(AllTrim(SubStr(cLine,nCol2+1)),Chr(34),"")}
         if lNFE
            nIdx := Len(aINI[_INI_NFES])
            AAdd(aINI[_INI_NFES][nIdx][2],aItem)
         else
            i1 := Len(aINI[_INI_SECTIONS])
            i2 := Len(aINI[_INI_SECTIONS][i1])
            AAdd(aINI[_INI_SECTIONS][i1][i2],aItem)
         end
      end
   end
   if nCol1 > Len(cContent)
      return aINI
   end
end


// Constrói um INI a partir de uma matriz com a estrutura do elemento 3 ([_INI_SECTIONS]) já descrito
// *************************************************************************************************
function BuildINI(aINI,nLinSep) // Opcional, o argumento nLinSep representa a quantidade de linhas
local cStrOut := ""             // que separarão as seções.
local cSection                  // Essa função constrói o INI a partir de uma matriz com a estrutura
local cProperty                 // do elemento 3 [_INI_SECTIONS] acima descrito.
local cValue
*
default nLinSep to 0
for j := 1 to Len(aINI)
    cSection := aINI[j][1]
    cStrOut  += if(j>1, Replicate(_EOL,nLinSep), "") + "[" + cSection + "]" + _EOL
    *
    for k := 1 to Len(aINI[j][2])
        cProperty := aINI[j][2][k][1]
        cValue    := aINI[j][2][k][2]
        cStrOut   += cProperty + "=" + cValue + _EOL
    next
next
return cStrOut


// Retorna o valor de uma propriedade, de uma certa seção.
// *************************************************************************************************
function GetINIProp(aINI,cSecName,cProperty) // aINI é a matriz de seções
static cSection
local  aLocation
*
cSection  := if(cSecName=VOID, cSection, cSecName)
aLocation := SearchINI(aINI,cSection,cProperty)
if aLocation[1] > 0
   return aINI[aLocation[1]][2][aLocation[2]][2]
end
return ""


// Procura pelas "coordenadas" de uma propriedade e sua seção dentro da matriz informada.
// *************************************************************************************************
function SearchINI(aINI,cSection,cProperty) // aINI é a matriz de seções
local nSection
local nProperty
*
nSection := AScan(aINI,{|a|Upper(a[1]) == Upper(AllTrim(cSection))})
if nSection > 0
   nProperty := AScan(aINI[nSection][2],{|a|Upper(a[1]) == Upper(AllTrim(cProperty))})
   if nProperty > 0
      return {nSection,nProperty}
   end
end
return {0,0}


// Atribui valor a uma propriedade, em uma certa seção.
// *************************************************************************************************
function SetINIProp(aINI,cSection,cProperty,cValue) // aINI é a matriz de seções
local aLocation := SearchINI(aINI,cSection,cProperty)
if aLocation[1] > 0
   aINI[aLocation[1]][2][aLocation[2]][2] := cValue
   return TRUE
end
return FALSE
Se alguém precisar, posso fazer algum código de exemplo de uso.

[Fonte Editado em 27/12/10]
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Avatar do usuário
janio
Colaborador
Colaborador
Mensagens: 1846
Registrado em: 06 Jul 2004 07:43
Localização: UBAJARA - CE

Re: Funções para o tratamento de arquivos INI

Mensagem por janio »

Pô Maligno,

Apesar da farta explicação que vc coloca no código (marca registrada), minha pequena cabecinha só consegue entender o negócio quando tem um exemplo real de uso. A falta de uma função como esta tem me levado a importar o arq retorno do Acbr para um dbf e aí tratá-lo. Não é uma maneira profissional mas é a que consegui fazer.

Posta um exemplo de uso aí que fico agradecidio. heheehe

:|< :{ :xau :f X:)

Janio
fui...
e-mail:janioaguiar@yahoo.com.br
msn: janio_aguiar@hotmail.com
xHarbour1.2.1/Harbour3.2 + wvg + hwgui + Mediator + MySql
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: Funções para o tratamento de arquivos INI

Mensagem por Maligno »

Suponhamos que você queira mudar o número do certificado que está no arquivo INI de configuração do ACBrNFeMonitor. Usando uma variável pública chamada aINI, o código poderia ser:

Código: Selecionar todos

#include "inifile.ch"

//**************************************************************
function LerACBrINI()
local cBuffer
local nFHandle := LF_FOpen(ACbrPath()+"ACBrNFeMonitor.ini")
*
aINI := {}
if nFHandle > 0
   cBuffer := Space(FSeek(nFHandle,0,2))
   FSeek(nFHandle,0,0)
   FRead(nFHandle,@cBuffer,Len(cBuffer))
   FClose(nFHandle)
   aINI := ExtractINI(cBuffer)
end
return nil

//**************************************************************
function GetCertific()
return GetINIProp(aINI[_INI_SECTIONS],"Certificado","Caminho")

//**************************************************************
function SetCertific(cNew)
SetINIProp(aINI[_INI_SECTIONS],"Certificado","Caminho",cNew)
return nil
Lembrando que a _INI_SECTIONS é o terceiro elemento da matriz aINI, conforme explicado no fonte. E veja então, que a função serve para qualquer INI, de qualquer programa. Usei o ACBrNFe apenas como exemplo. Aliás, se no lugar de _INI_SECTIONS você informar o quarto elemento (_INI_NFES), também poderá acessar os valores das propriedades da mesma forma. O que muda é apenas a sub-matriz alvo da pesquisa.
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Re: Funções para o tratamento de arquivos INI

Mensagem por asimoes »

Senhores,

Importantissima contribuição do nosso colega Maligno, aproveitando este tópico para contribuir com um exemplo do harbour.
Para usar este exemplo deve ser usado a lib xhb, esta função foi portada do xharbour

Código: Selecionar todos

FUNCTION Main
LOCAL hWrite := Hash(), hRead:= HB_ReadIni( "TESTE.INI" )
IF !FILE("TESTE.INI")

      hWrite["MAIN" ]           := Hash()
      hWrite["MAIN" ]["Desc" ]  := "Application program"
      hWrite["MAIN" ]["Ver"  ]  := "Version 2.2"

      hWrite["Path" ]           := Hash()
      hWrite["Path" ]["DATA"]   := "\apps\data\"
      hWrite["Path" ]["CONFIG"] := "\apps\conf\"

      hWrite["Files"]           := Hash()
      hWrite["Files"]["DB1"]    := "Customer.dbf"
      hWrite["Files"]["DB2"]    := "Sales.dbf"

      HB_WriteIni( "teste.ini", hWrite,"; Start comment", "; End comment" )
ELSE
    ? hRead["Path"]["DATA"] 
ENDIF
INKEY(0)
RETURN NIL
Conteudo do teste.ini

Código: Selecionar todos

; Start comment
Ver = Version 2.2
Desc = Application program

[Path]
DATA=\apps\data\
CONFIG=\apps\conf\

[Files]
DB1=Customer.dbf
DB2=Sales.dbf
; End comment
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Re: Funções para o tratamento de arquivos INI

Mensagem por fladimir »

Legal, parabéns colega...

Agora faço muita confusão alguém poderia explicar como a linha abaixo do arquivo de cabeçalho

Código: Selecionar todos

#xcommand DEFAULT  TO  =>  := if( = nil, , )
afeta essa linha presente no código:

Código: Selecionar todos

default nLinSep to 0
Tipo com palavras simples o q ocorre?

Não gostaria de saber somente a nível geral do Código mas no literal qdo uso o #xcomand como definido acima e depois no código usa-se de outro jeito, qual o sentido?

Pq não fazer direto no código já traduzido (acredito q seja algo do tipo)....

Até hoje não entendi direito códigos qdo vejo com cabeçalhos descrevendo #xcommand...
O #define penso q entendo, mas o #xcommand, acredito q tem tb o #translate e outros não entendo nada e me confundo qdo vejo nos códigos.

Sds..

Sucesso!!!

:)Pos
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: Funções para o tratamento de arquivos INI

Mensagem por Maligno »

Em palavras simples, ocorre o seguinte:

Código: Selecionar todos

#xcommand DEFAULT <var> TO <defvl>      =>     <var> := if(<var> = nil, <defvl>, <var>)
O pré-compilador, que vai traduzir isso, vai apenas trocar um comando pela expressão equivalente, conforme foi configurado. Ou seja, ele vai pegar os valores (<var> e <defvl>) à esquerda da flecha e vai "transferí-los" para a expressão à direita, como se eu próprio tivesse digitado. É apenas uma forma de tornar algumas expressões complexas mais fáceis de montar e ler.

Se quiser continuar a discutir a respeito desse recurso, crie um tópico à parte, para evitar misturar os assuntos.
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Avatar do usuário
fladimir
Colaborador
Colaborador
Mensagens: 2445
Registrado em: 15 Nov 2006 20:21

Re: Funções para o tratamento de arquivos INI

Mensagem por fladimir »

Entendi já Maligno eu mais ou meno tinha idéia, agora com tua explicação entendi e compreendi.

Grato.

:)Pos
Sun Tzu há mais de três mil anos cita nas epígrafes de seu livro “A Arte da Guerra“:

“Concentre-se nos pontos fortes, reconheça as fraquezas, agarre as oportunidades e proteja-se contra as ameaças”.
“Se não é vantajoso, nunca envie suas tropas; se não lhe rende ganhos, nunca utilize seus homens; se não é uma situação perigosa, nunca lute uma batalha precipitada”
.


Até 2017    Desktop Console [ Legado ] Harbour | MinGW | DBF | CDX | FastReport | MySQL


Novos Projetos:

   Desktop Visual           Windev Desktop
   Celular Android/iOS   Windev Mobile
   WEB                            Windev Web


Sejamos gratos a Deus.
lucimauro
Usuário Nível 3
Usuário Nível 3
Mensagens: 465
Registrado em: 21 Set 2004 21:02
Localização: Sobral-CE

Re: Funções para o tratamento de arquivos INI

Mensagem por lucimauro »

Estou tentando usar essa funcao mais quando compilo ta dando que a variavel VOID nao estive.
Voce poderia me ajudar a resolver.

Desde ja agradeço.
lucimauro
Usuário Nível 3
Usuário Nível 3
Mensagens: 465
Registrado em: 21 Set 2004 21:02
Localização: Sobral-CE

Re: Funções para o tratamento de arquivos INI

Mensagem por lucimauro »

O erro acima eu ja conseguir resolver.

tenho esse arquivo :
OK: [ECF]
DataMovimento = 15/12/10
NumSerie = BE050875610000022139
NumLoja = 0001
NumECF = 0003
NumCOO = 018739
NumCRZ = 0153
NumCRO = 0002

[Aliquotas]
01T1700 = 0
02T0700 = 0
03T0350 = 0
04T1000 = 0
05T1200 = 0
06T2500 = 0
07T2700 = 0

[OutrasICMS]
TotalSubstituicaoTributaria = 20
TotalNaoTributado = 0
TotalIsencao = 0

[NaoFiscais]
SA_Sangria = 0
SU_Suprimento = 0

[Totalizadores]
TotalDescontos = 0
TotalCancelamentos = 0
TotalAcrescimos = 0
TotalNaoFiscal = 0
VendaBruta = 20
GrandeTotal = 231120,53


Como faço para pegar o [TOTALIZARDORE]
[VENDABRUTA] porque aqui tentei e nao conseguir..
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: Funções para o tratamento de arquivos INI

Mensagem por Maligno »

É a mesma forma que usei no exemplo acima, de certificados do ACBr. Veja:

Código: Selecionar todos

GetINIProp(aINI[_INI_SECTIONS],"Totalizadores","VendaBruta")
Tentou dessa forma? Como está o código que deu erro?
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
lucimauro
Usuário Nível 3
Usuário Nível 3
Mensagens: 465
Registrado em: 21 Set 2004 21:02
Localização: Sobral-CE

Re: Funções para o tratamento de arquivos INI

Mensagem por lucimauro »

Obrigado miligon por sua resposta.
na verdade nao expliquei direito.
o que acontece é que fiz do jeito que voce me disse acima, so que retorna ""(branco), que na verdade era para retornar 20(vinte) certo.
lucimauro
Usuário Nível 3
Usuário Nível 3
Mensagens: 465
Registrado em: 21 Set 2004 21:02
Localização: Sobral-CE

Re: Funções para o tratamento de arquivos INI

Mensagem por lucimauro »

Tambem nao se se o erro pode ter acontecido,por eu ter modificacado essa linha ja que tava dando variavel VOID nao existe

cSection := if(cSecName=VOID, cSection, cSecName)
por
cSection := cSecName
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: Funções para o tratamento de arquivos INI

Mensagem por Maligno »

Mostra o código que está dando erro. Senão fica difícil opinar.
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
lucimauro
Usuário Nível 3
Usuário Nível 3
Mensagens: 465
Registrado em: 21 Set 2004 21:02
Localização: Sobral-CE

Re: Funções para o tratamento de arquivos INI

Mensagem por lucimauro »

Código: Selecionar todos

nfhandle:=fopen("sai.txt")
 cBuffer :=Space(FSeek(nFHandle,0,2))
 FSeek(nFHandle,0,0)
 FRead(nFHandle,@cBuffer,Len(cBuffer))
 FClose(nFHandle)
 aIni:=extractini(cBuffer)
 teste1:=getIniprop(aINI[_INI_SECTIONS],"Totalizadores","VendaBruta")
 @ 10,10 say teste1


O arquivo sai.txt é o arquivo que ja postei na mensagem anterior.

Abaixa segue sua funcao.

Código: Selecionar todos

 // *************************************************************************************************
 // A matriz de retorno desta função não está ligada à configuração do ACBrNFeMonitor mas as demais
 // funções de manipulação de =posthilit>INI</SPAN> não tem essa ligação. Ou seja, aINI[3] (configuração) e aINI[4]
 // (NFe) devem ser informadas isoladamente para essas funções de apoio. Ademais, essa funções podem
 // ser utilizadas em qualquer =posthilit>arquivo</SPAN> =posthilit>INI</SPAN> que não tenha vínculo com a estrutura do ACBrNFeMonitor.
 // *************************************************************************************************
 function ExtractINI(cContent) // O conteúdo inteiro do =posthilit>INI</SPAN> que, normalmente, é um =posthilit>arquivo</SPAN> pequeno.
 local cSection                //
 local nCol1                   //
 local nCol2                   //
 local cSymb                   //
 local aItem                   //
 local i1                      //
 local i2                      //
 local lNFe := _FALSE          // se _TRUE, está lendo dados de uma NFe.
 local aINI := {0,"",{},{}}    // Elementos: 1=se for o número 0, indicará sucesso na leitura
                               //                     Obs: havendo erro, será devolvido o valor -1
                               //            2=texto encontrado antes da primeira seção ("", se não existir)
                               //            3=matriz de seções, que conterá matrizes com dois elementos:
                               //                     1=nome da seção
                               //                     2=matriz de propriedades, que conterá dois elementos:
                               //                                 1=nome da propriedade
                               //                                 2=conteúdo
                               //            4=matriz de NFes, conterá matrizes com dois elementos:
                               //                     1=número da NFe (texto, sem o prefixo "NFE")
                               //                     2=matriz de propriedades da NFe, com dois elementos:
                               //                                 1=nome da propriedade
                               //                                 2=conteúdo

 // Alguns INIs terminam sem um par CR/LF. Fica mais fácil analisar se ele existir.
 cContent += _EOL

 // Se o =posthilit>INI</SPAN> contiver algum texto antes de qualquer símbolo, ele será copiado
 // integralmente para o segundo elemento da matriz de retorno. Um caso assim
 // ocorre no =posthilit>arquivo</SPAN> de retorno do ACBrNFeMonitor.
 if (nCol1 := At("[",cContent)) = 0
    // Se não for um =posthilit>INI</SPAN> válido, não há o que fazer.
    return {-1,cContent} // retorna apenas dois elementos: o erro no primeiro e o próprio conteúdo no segundo
 end

 // Pode haver um texto antes da primeira seção.
 if nCol1 > 1
    nCol2 := At(_EOL,cContent)
    nCol2 := if(nCol2=0, nCol1-1, nCol2-1)
    aINI[_INI_TEXT] := SubStr(cContent,1,nCol2)
 end

 // Cada linha será tratada individualmente, começando pela primeira seção.
 // Serão armazenados todos os pares (XXX=YYY) em sub-matrizes dentro da
 // seção atualmente aberta. A variável "nCol1" vai percorrer as linhas,
 // sempre parando no primeiro caractere de cada uma, para a próxima iteração.
 while _TRUE
    // Separar a linha, ja suprimindo o par CR/LF (dois inúteis).
    nCol2 := At(_EOL,SubStr(cContent,nCol1))+nCol1-1
    cLine := AllTrim(SubStr(cContent,nCol1,nCol2-nCol1))
    nCol1 := nCol2+_EOL_SIZE

    if Left(cLine,1) = "["
       nCol2 := At("]",cLine)
       cSymb := SubStr(cLine,2,nCol2-2)
       *
       if (lNFe := Left(cSymb,3) = "NFE")
          AAdd(aINI[_INI_NFES],{SubStr(cSymb,4),{}})
       else
          AAdd(aINI[_INI_SECTIONS],{cSymb,{}})
       end
    else
       // Se o operador de atribuição não for encontrado, a linha será ignorada por completo.
       if (nCol2 := At("=",cLine)) > 0
          aItem := {Left(cLine,nCol2-1),SubStr(cLine,nCol2+1)}
          if lNFE
             nIdx := Len(aINI[_INI_NFES])
             AAdd(aINI[_INI_NFES][nIdx],aItem)
          else
             i1 := Len(aINI[_INI_SECTIONS])
             i2 := Len(aINI[_INI_SECTIONS][i1])
             AAdd(aINI[_INI_SECTIONS][i1][i2],aItem)
          end
       end
    end
    if nCol1 > Len(cContent)
       return aINI
    end
 end


 // Constrói um =posthilit>INI</SPAN> a partir de uma matriz com a estrutura do elemento 3 ([_INI_SECTIONS]) já descrito
 // *************************************************************************************************
 function BuildINI(aINI,nLinSep) // Opcional, o argumento nLinSep representa a quantidade de linhas
 local cStrOut := ""             // que separarão as seções.
 local cSection                  // Essa função constrói o =posthilit>INI</SPAN> a partir de uma matriz com a estrutura
 local cProperty                 // do elemento 3 [_INI_SECTIONS] acima descrito.
 local cValue
 *
 default nLinSep to 0
 for j := 1 to Len(aINI)
     cSection := aINI[j][1]
     cStrOut  += if(j>1, Replicate(_EOL,nLinSep), "") + "[" + cSection + "]" + _EOL
     *
     for k := 1 to Len(aINI[j][2])
         cProperty := aINI[j][2][k][1]
         cValue    := aINI[j][2][k][2]
         cStrOut   += cProperty + "=" + cValue + _EOL
     next
 next
 return cStrOut


 // Retorna o valor de uma propriedade, de uma certa seção.
 // *************************************************************************************************
 function GetINIProp(aINI,cSecName,cProperty) // aINI é a matriz de seções
 static cSection
 local  aLocation
 *
 cSection  := cSecName
*cSection  := if(cSecName=VOID, cSection, cSecName)
 aLocation := SearchINI(aINI,cSection,cProperty)
 if aLocation[1] > 0
    return aINI[aLocation[1]][2][aLocation[2]][2]
 end
 return ""


 // Procura pelas "coordenadas" de uma propriedade e sua seção dentro da matriz informada.
 // *************************************************************************************************
 function SearchINI(aINI,cSection,cProperty) // aINI é a matriz de seções
 local nSection
 local nProperty
 *
 nSection := AScan(aINI,{|a|Upper(a[1]) == Upper(cSection)})
 if nSection > 0
    nProperty := AScan(aINI[nSection][2],{|a|Upper(a[1]) == Upper(cProperty)})
    if nProperty > 0
       return {nSection,nProperty}
    end
 end
 return {0,0}


 // Atribui valor a uma propriedade, em uma certa seção.
 // *************************************************************************************************
 function SetINIProp(aINI,cSection,cProperty,cValue) // aINI é a matriz de seções
 local aLocation := SearchINI(aINI,cSection,cProperty)
 if aLocation[1] > 0
    aINI[aLocation[1]][2][aLocation[2]][2] := cValue
    return _TRUE
 end
 return _FALSE
Editado pela última vez por Maligno em 27 Dez 2010 15:54, em um total de 2 vezes.
Razão: Mensagem editada para colocar a tag [ code ]<br>Veja como utilizar esta tag: http://www.pctoledo.com.br/forum/faq.php?mode=bbcode#f2r1
Avatar do usuário
Maligno
Membro Master
Membro Master
Mensagens: 6398
Registrado em: 06 Jul 2004 01:40
Localização: Londrina/PR

Re: Funções para o tratamento de arquivos INI

Mensagem por Maligno »

Na verdade, foi uma falha da minha parte. Ao extrair os símbolos do INI não removi os espaços em branco que podem existir antes/depois do sinal de igual das propriedades. Por isso sua busca retornava errada. Modifiquei o fonte da primeira mensagem do tópico. Agora os espaços são eliminados na extração e, adicionalmente, também são eliminadas as aspas, caso existam. Na pesquisa, a string a pesquisar também tem seus espaços eliminados.

Acho que agora deve funcionar perfeitamente. :)
[]'s
Maligno
---
Não respondo questões técnicas através de MP ou eMail. Não insista.
As dúvidas devem ser postadas no fórum. Desta forma, todos poderão
se beneficiar das respostas.

---
Se um dia precisar de uma transfusão de sangue você perceberá como
é importante a figura do doador. Procure o hemocentro de sua cidade e
se informe sobre a doação de sangue, plaquetas e medula óssea. Doe!
Responder