Funções para o tratamento de arquivos INI
Enviado: 08 Ago 2010 10:53
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:
Se alguém precisar, posso fazer algum código de exemplo de uso.
[Fonte Editado em 27/12/10]
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
[Fonte Editado em 27/12/10]