Here is the code of a kind of library "tagfile", I developed more than ten years ago, that I maintain and I always use for the management of my configuration *.ini files.
That works under Windows (CVI) or any UNIX system.
The code enables:
- to read and write tags
- to list the sections of an ini file
- to list the tags of a section
- to trap the errors
Most of others ideas about this issue on this blog are written under LabView ; I think a pure C code could be useful for some developers.
Comments are written in French but could be easily translated by any web AI API.
Below are example of functions for reading and writing a ini file. These functions are extracted from a program devoted to the dynamic excitation of a structure (mechanics).
Example of ini file
# --------------------------------------------
# DYNAMICS.INI
# Configuration "gros marteau"
# E.Ringot - BLUESPINE SAS - FRANCE
# https://www.blue-spine.com
# --------------------------------------------
[Sounds]
BUZZER = 0
SPEECH = 1
SPEECHSPEED = 1
SPEECHVOLUME = 93
#
# --------------------------------------------
[sampling]
# rate : Hz
# duration : s
PREFIX = BS
AUTOIMPACT = 6796480
RATE = 20000
DURATION = 10.000000
NBLOCKS = 32
#
# --------------------------------------------
[force]
# sensitivity : mV/N
# valmax : N
# excitation current : mA
DAQCHANNEL = cDAQ1Mod1/ai0
SENSITIVITY_0 = 0.233800
SENSITIVITY_1 = 0.233800
CURRENT = 20.000000
VALMAX = 21385.000000
#
# --------------------------------------------
[pretrigger]
# threshold : N
# hysfactor : no unit
THRESHOLD = 200.000000
HYSTFACTOR = 1.010000
REJECTION = 1000.000000
#
# --------------------------------------------
[acceleration]
# sensitivity : mV/g !!!
# valmax : m/s2
# excitation current : mA
DAQCHANNEL = cDAQ1Mod1/ai1
MODEL = PCB 35C33
SN = LW232997
SENSITIVITY = 101.000000
CURRENT = 10.000000
VALMAX = 480.000000
VALMA_x = 490.000000
#
# --------------------------------------------
[hammer]
# PCB Piezotronics impact hammer
MODEL = PCB 086D20
SN = 45451
TIP0 = GREY: Super soft
RANGE0 = 400
TIP1 = BROWN: Soft
RANGE1 = 450
TIP2 = RED: Medium
RANGE2 = 560
TIP3 = BLACK: Hard
RANGE3 = 1000
TIP4 =
RANGE4 = 0
TIP5 =
RANGE5 = 0
TIP6 =
RANGE6 = 0
TIP7 =
RANGE7 = 0
INDEX = 0
EXTENDER = 0
#
# --------------------------------------------
[post]
#
HMIN = 1.000000E-09
HMAX = 0.001000
HAUTO = 36180524
FLOW = 10.000000
FCUT = 100.000000
FAUTO = 36180524
# --------------------------------------------
FLOW = 10.000000
FCUT = 100.000000
[histo]
DIR0 = C:\dir0
DIR1 = C:\dir1
DIR4 = C:\Users\ringot\Documents\My Teaching\M1_DYNAMIQUE\tp\NI-CVI\polytp
DIR2 = C:\Users\ringot\Documents\My Teaching\M1_DYNAMIQUE\tp\NI-CVI\UT_Hammer
DIR3 = C:\Users\ringot\Documents\My Teaching\M1_DYNAMIQUE\tp\NI-CVI\UT_Newton
DIR5 = C:\Users\ringot\Documents\My Teaching\M1_DYNAMIQUE\tp\NI-CVI\UT_Newton
DIR6 = C:\Users\ringot\Documents\My Teaching\M1_DYNAMIQUE\tp\NI-CVI\UT_ForceOne
# --- EOF ---
Example of ini file reading
/* ---------------------------------------------------------------
LoadIni
Lecture du fichier inifile
--------------------------------------------------------------- */
int LoadIni(void)
{
#define cx cell.x
#define cy cell.y
Point cell;
int n, flag;
char *section;
long val;
section="sounds";
ReadShortTag(inifile,section,"BUZZER",(short*)&buzzer);
SetCtrlVal(tab4,TAB4_BUZZER,buzzer);
ReadShortTag(inifile,section,"SPEECH",(short*)&speech);
SetCtrlVal(tab4,TAB4_SPEECH,speech);
ReadShortTag(inifile,section,"VOICE",(short*)&voice);
SetCtrlVal(tab4,TAB4_VOICE,voice);
ReadLongTag(inifile,section,"SPEECHSPEED",&speech_speed);
SetCtrlVal(tab4,TAB4_SPEECHSPEED,speech_speed);
ReadLongTag(inifile,section,"SPEECHVOLUME",&speech_volume);
SetCtrlVal(tab4,TAB4_SPEECHVOLUME,speech_volume);
section="sampling";
TagErrChk(ReadLongTag(inifile,section,"RATE",&val));
SetCtrlVal(tab0,TAB0_RATE,rate=val);
TagErrChk(ReadDoubleTag(inifile,section,"DURATION",&duration));
SetCtrlVal(tab0,TAB0_DURATION,duration);
TagErrChk(ReadLongTag(inifile,section,"NBLOCKS",&nblocks));
SetCtrlVal(tab0,TAB0_NBLOCKS,nblocks);
TagErrChk(ReadIntTag(inifile,section,"AUTOIMPACT",&autoimpact));
SetCtrlVal(tab0,TAB0_AUTOIMPACT,autoimpact);
TagErrChk(ReadStringTag(inifile,section,"PREFIX",prefix));
if (!*prefix) strcpy(prefix,"CORROHM");
SetCtrlVal(tab0,TAB0_PREFIX,prefix);
section="force";
TagErrChk(ReadStringTag(inifile,section,"DAQCHANNEL",forceChannel));
SetCtrlVal(tab1,TAB1_DAQCHANNEL,forceChannel);
TagErrChk(ReadDoubleTag(inifile,section,"SENSITIVITY_0",forceSensitivityList));
SetCtrlVal(tab1,TAB1_SENSITIVITY_0,forceSensitivityList[0]);
TagErrChk(ReadDoubleTag(inifile,section,"SENSITIVITY_1",forceSensitivityList+1));
SetCtrlVal(tab1,TAB1_SENSITIVITY_1,forceSensitivityList[1]);
TagErrChk(ReadDoubleTag(inifile,section,"CURRENT",&forceExcitationCurrent));
SetCtrlVal(tab1,TAB1_CURRENT,forceExcitationCurrent);
TagErrChk(ReadDoubleTag(inifile,section,"VALMAX",&forceMax));
SetCtrlVal(tab1,TAB1_VALMAX,forceMax);
section="pretrigger";
TagErrChk(ReadDoubleTag(inifile,section,"REJECTION",&rejection));
SetCtrlVal(tab1,TAB1_REJECTION,rejection);
TagErrChk(ReadDoubleTag(inifile,section,"THRESHOLD",&threshold));
SetCtrlVal(tab1,TAB1_THRESHOLD,threshold);
TagErrChk(ReadDoubleTag(inifile,section,"HYSTFACTOR",&hystfactor));
SetCtrlVal(tab1,TAB1_HYSTFACTOR,hystfactor);
section="acceleration";
TagErrChk(ReadStringTag(inifile,section,"DAQCHANNEL",accelChannel));
SetCtrlVal(tab2,TAB2_DAQCHANNEL,accelChannel);
TagErrChk(ReadDoubleTag(inifile,section,"SENSITIVITY",&accelSensitivity));
SetCtrlVal(tab2,TAB2_SENSITIVITY,accelSensitivity);
TagErrChk(ReadDoubleTag(inifile,section,"CURRENT",&accelExcitationCurrent));
SetCtrlVal(tab2,TAB2_CURRENT,accelExcitationCurrent);
TagErrChk(ReadDoubleTag(inifile,section,"VALMAX",&accelMax));
SetCtrlVal(tab2,TAB2_VALMAX,accelMax);
TagErrChk(ReadStringTag(inifile,section,"MODEL",amodel));
SetCtrlVal(tab2,TAB2_MODEL,amodel);
TagErrChk(ReadStringTag(inifile,section,"SN",aSN));
SetCtrlVal(tab2,TAB2_SN,aSN);
//
AllocateMemory();
//
section="hammer";
TagErrChk(ReadStringTag(inifile,section,"MODEL",fmodel));
SetCtrlVal(tab1,TAB1_MODEL,fmodel);
TagErrChk(ReadStringTag(inifile,section,"SN",fSN));
SetCtrlVal(tab1,TAB1_SN,fSN);
// tips
GetNumListItems(hammerHandle, HAMMER_TIPLIST, &n);
DeleteListItem (hammerHandle, HAMMER_TIPLIST, 0, n);
GetNumTableRows (tab3, TAB3_TABLE, &n);
DeleteTableRows (tab3, TAB3_TABLE, 1, n);
cy = 1; n = 0;
do {
char var[8], label[64];
int ftip;
sprintf(var,"TIP%d",n);
if (ReadStringTag(inifile,section,var,label)) break;
if (!*label) break;
sprintf(var,"RANGE%d",n);
if (ReadLongTag(inifile,section,var,&ftip)) break;
if (!ftip) break;
InsertListItem(hammerHandle, HAMMER_TIPLIST,-1,label,ftip);
InsertTableRows (tab3, TAB3_TABLE,-1, 1, VAL_USE_MASTER_CELL_TYPE);
cx=COL_TIP; SetTableCellVal(tab3,TAB3_TABLE,cell,label);
cx=COL_FRQ; SetTableCellVal(tab3,TAB3_TABLE,cell,ftip);
cy++; n++;
} while(1);
SetCtrlVal(tab3,TAB3_NTIPS,n);
if (ReadLongTag(inifile,section,"INDEX",&n)) n=0;
SetCtrlIndex(hammerHandle,HAMMER_TIPLIST,n);
cx=COL_SEL; cy=n+1;
SetTableCellVal(tab3,TAB3_TABLE,cell,"X");
TagErrChk(ReadLongTag(inifile,section,"EXTENDER",&flag));
SetCtrlVal(hammerHandle,HAMMER_RADIOEXTENDER,flag);
forceSensitivity=forceSensitivityList[flag];
// dir history
TagErrChk(ReadHistoDir(inifile));
tagstop:
return tagerr;
#undef cx
#undef cy
} // LoadIni
Example of ini file writing
/* ---------------------------------------------------------------
SaveIni
Sauvegarde du fichier inifile
--------------------------------------------------------------- */
int SaveIni(void)
{
#define cx cell.x
#define cy cell.y
Point cell;
int tipindex=0, n;
char *section;
// -- TAB4
section="Sounds";
GetCtrlVal(tab4,TAB4_BUZZER,&n);
WriteShortTag(inifile,section,"BUZZER",buzzer=(short)n);
GetCtrlVal(tab4,TAB4_SPEECH,&n);
WriteShortTag(inifile,section,"SPEECH",speech=(short)n);
GetCtrlVal(tab4,TAB4_SPEECHSPEED,&speech_speed);
WriteLongTag(inifile,section,"SPEECHSPEED",speech_speed);
GetCtrlVal(tab4,TAB4_SPEECHVOLUME,&speech_volume);
WriteLongTag(inifile,section,"SPEECHVOLUME",speech_volume);
// -- TAB0
section="sampling";
GetCtrlVal(tab0,TAB0_RATE,&rate);
TagErrChk(WriteLongTag(inifile,section,"RATE",rate));
GetCtrlVal(tab0,TAB0_DURATION,&duration);
TagErrChk(WriteDoubleTag(inifile,section,"DURATION",duration));
GetCtrlVal(tab0,TAB0_NBLOCKS,&nblocks);
TagErrChk(WriteLongTag(inifile,section,"NBLOCKS",nblocks));
GetCtrlVal(tab0,TAB0_AUTOIMPACT,&autoimpact);
TagErrChk(WriteIntTag(inifile,section,"AUTOIMPACT",autoimpact));
GetCtrlVal(tab0,TAB0_PREFIX,prefix);
TagErrChk(WriteStringTag(inifile,section,"PREFIX",StrClean(prefix)));
// -- TAB1
section="force";
GetCtrlVal(tab1,TAB1_DAQCHANNEL,forceChannel);
TagErrChk(WriteStringTag(inifile,section,"DAQCHANNEL",forceChannel));
GetCtrlVal(tab1,TAB1_SENSITIVITY_0,forceSensitivityList);
TagErrChk(WriteDoubleTag(inifile,section,"SENSITIVITY_0",forceSensitivityList[0]));
GetCtrlVal(tab1,TAB1_SENSITIVITY_1,forceSensitivityList+1);
TagErrChk(WriteDoubleTag(inifile,section,"SENSITIVITY_1",forceSensitivityList[1]));
GetCtrlVal(tab1,TAB1_CURRENT,&forceExcitationCurrent);
TagErrChk(WriteDoubleTag(inifile,section,"CURRENT",forceExcitationCurrent));
GetCtrlVal(tab1,TAB1_VALMAX,&forceMax);
TagErrChk(WriteDoubleTag(inifile,section,"VALMAX",forceMax));
section="pretrigger";
GetCtrlVal(tab1,TAB1_REJECTION,&rejection);
TagErrChk(WriteDoubleTag(inifile,section,"REJECTION",rejection));
GetCtrlVal(tab1,TAB1_THRESHOLD,&threshold);
TagErrChk(WriteDoubleTag(inifile,section,"THRESHOLD",threshold));
GetCtrlVal(tab1,TAB1_HYSTFACTOR,&hystfactor);
TagErrChk(WriteDoubleTag(inifile,section,"HYSTFACTOR",hystfactor));
// -- TAB2
section="acceleration";
GetCtrlVal(tab2, TAB2_MODEL,fmodel);
TagErrChk(WriteStringTag(inifile,section,"MODEL",amodel));
GetCtrlVal(tab2, TAB2_SN,fSN);
TagErrChk(WriteStringTag(inifile,section,"SN",aSN));
GetCtrlVal(tab2,TAB2_DAQCHANNEL,accelChannel);
TagErrChk(WriteStringTag(inifile,section,"DAQCHANNEL",accelChannel));
GetCtrlVal(tab2,TAB2_SENSITIVITY,&accelSensitivity);
TagErrChk(WriteDoubleTag(inifile,section,"SENSITIVITY",accelSensitivity));
GetCtrlVal(tab2,TAB2_CURRENT,&accelExcitationCurrent);
TagErrChk(WriteDoubleTag(inifile,section,"CURRENT",accelExcitationCurrent));
GetCtrlVal(tab2,TAB2_VALMAX,&accelMax);
TagErrChk(WriteDoubleTag(inifile,section,"VALMAX",accelMax));
// -- TAB3
section="hammer";
GetCtrlVal(tab1, TAB1_MODEL,fmodel);
TagErrChk(WriteStringTag(inifile,section,"MODEL",fmodel));
GetCtrlVal(tab1, TAB1_SN,fSN);
TagErrChk(WriteStringTag(inifile,section,"SN",fSN));
// tips
GetNumListItems(hammerHandle, HAMMER_TIPLIST, &n);
DeleteListItem (hammerHandle, HAMMER_TIPLIST, 0, n);
GetNumTableRows (tab3, TAB3_TABLE, &n);
for (cy=1; cy<=MAX_NBTIPS; cy++)
{
char var1[8], var2[16], label[64];
int k=cy-1, ftip;
sprintf(var1,"TIP%d",k);
sprintf(var2,"RANGE%d",k);
if (cy<=n)
{
cx=COL_SEL; GetTableCellVal(tab3,TAB3_TABLE,cell,label);
if (*label=='X') tipindex=cy-1;
cx=COL_TIP; GetTableCellVal(tab3,TAB3_TABLE,cell,label);
cx=COL_FRQ; GetTableCellVal(tab3,TAB3_TABLE,cell,&ftip);
InsertListItem(hammerHandle,HAMMER_TIPLIST,-1,label,ftip);
}
else
{
*label=0; ftip=0;
}
TagErrChk(WriteStringTag(inifile,section,var1,label));
TagErrChk(WriteLongTag(inifile,section,var2,ftip));
}
SetCtrlIndex(hammerHandle,HAMMER_TIPLIST,tipindex);
TagErrChk(WriteLongTag(inifile,section,"INDEX",tipindex));
//
AllocateMemory();
//
TagErrChk(WriteHistoDir(inifile));
tagstop:
return tagerr;
#undef cx
#undef cy
} // SaveIni