3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 DBG_DEFAULT_CHANNEL(INIFILE
);
25 LIST_ENTRY IniFileSectionListHead
= {&IniFileSectionListHead
, &IniFileSectionListHead
};
26 BOOLEAN IniFileSectionInitialized
= FALSE
;
27 ULONG IniFileSectionCount
= 0;
28 ULONG IniFileSettingCount
= 0;
31 BOOLEAN
IniParseFile(PCHAR IniFileData
, ULONG IniFileSize
)
34 ULONG CurrentLineNumber
;
36 ULONG IniFileLineSize
;
38 PINI_SECTION CurrentSection
= NULL
;
39 PINI_SECTION_ITEM CurrentItem
= NULL
;
41 TRACE("IniParseFile() IniFileSize: %d\n", IniFileSize
);
43 if (!IniFileSectionInitialized
)
45 InitializeListHead(&IniFileSectionListHead
);
46 IniFileSectionInitialized
= TRUE
;
49 // Start with an 80-byte buffer
51 IniFileLine
= FrLdrTempAlloc(IniFileLineSize
, TAG_INI_FILE
);
57 // Loop through each line and parse it
58 CurrentLineNumber
= 0;
60 while (CurrentOffset
< IniFileSize
)
62 // First check the line size and increase our buffer if necessary
63 if (IniFileLineSize
< IniGetNextLineSize(IniFileData
, IniFileSize
, CurrentOffset
))
65 IniFileLineSize
= IniGetNextLineSize(IniFileData
, IniFileSize
, CurrentOffset
);
66 FrLdrTempFree(IniFileLine
, TAG_INI_FILE
);
67 IniFileLine
= FrLdrTempAlloc(IniFileLineSize
, TAG_INI_FILE
);
74 // Get the line of data
75 CurrentOffset
= IniGetNextLine(IniFileData
, IniFileSize
, IniFileLine
, IniFileLineSize
, CurrentOffset
);
76 LineLength
= (ULONG
)strlen(IniFileLine
);
78 // If it is a blank line or a comment then skip it
79 if (IniIsLineEmpty(IniFileLine
, LineLength
) || IniIsCommentLine(IniFileLine
, LineLength
))
85 // Check if it is a new section
86 if (IniIsSectionName(IniFileLine
, LineLength
))
88 // Allocate a new section structure
89 CurrentSection
= FrLdrTempAlloc(sizeof(INI_SECTION
), TAG_INI_SECTION
);
92 FrLdrTempFree(IniFileLine
, TAG_INI_FILE
);
96 RtlZeroMemory(CurrentSection
, sizeof(INI_SECTION
));
98 // Allocate the section name buffer
99 CurrentSection
->SectionName
= FrLdrTempAlloc(IniGetSectionNameSize(IniFileLine
, LineLength
), TAG_INI_NAME
);
100 if (!CurrentSection
->SectionName
)
102 FrLdrTempFree(CurrentSection
, TAG_INI_FILE
);
103 FrLdrTempFree(IniFileLine
, TAG_INI_FILE
);
107 // Get the section name
108 IniExtractSectionName(CurrentSection
->SectionName
, IniFileLine
, LineLength
);
109 InitializeListHead(&CurrentSection
->SectionItemList
);
111 // Add it to the section list head
112 IniFileSectionCount
++;
113 InsertTailList(&IniFileSectionListHead
, &CurrentSection
->ListEntry
);
119 // Check if it is a setting
120 if (IniIsSetting(IniFileLine
, LineLength
))
122 // First check to make sure we're inside a [section]
123 if (CurrentSection
== NULL
)
125 ERR("Error: freeldr.ini:%lu: Setting '%s' found outside of a [section].\n", CurrentLineNumber
, IniFileLine
);
132 // Allocate a new item structure
133 CurrentItem
= FrLdrTempAlloc(sizeof(INI_SECTION_ITEM
), TAG_INI_SECTION_ITEM
);
136 FrLdrTempFree(IniFileLine
, TAG_INI_FILE
);
140 RtlZeroMemory(CurrentItem
, sizeof(INI_SECTION_ITEM
));
142 // Allocate the setting name buffer
143 CurrentItem
->ItemName
= FrLdrTempAlloc(IniGetSettingNameSize(IniFileLine
, LineLength
), TAG_INI_NAME
);
144 if (!CurrentItem
->ItemName
)
146 FrLdrTempFree(CurrentItem
, TAG_INI_SECTION_ITEM
);
147 FrLdrTempFree(IniFileLine
, TAG_INI_FILE
);
151 // Allocate the setting value buffer
152 CurrentItem
->ItemValue
= FrLdrTempAlloc(IniGetSettingValueSize(IniFileLine
, LineLength
), TAG_INI_VALUE
);
153 if (!CurrentItem
->ItemValue
)
155 FrLdrTempFree(CurrentItem
->ItemName
, TAG_INI_NAME
);
156 FrLdrTempFree(CurrentItem
, TAG_INI_SECTION_ITEM
);
157 FrLdrTempFree(IniFileLine
, TAG_INI_FILE
);
161 // Get the section name
162 IniExtractSettingName(CurrentItem
->ItemName
, IniFileLine
, LineLength
);
163 IniExtractSettingValue(CurrentItem
->ItemValue
, IniFileLine
, LineLength
);
165 // Add it to the current section
166 IniFileSettingCount
++;
167 CurrentSection
->SectionItemCount
++;
168 InsertTailList(&CurrentSection
->SectionItemList
, &CurrentItem
->ListEntry
);
177 FrLdrTempFree(IniFileLine
, TAG_INI_FILE
);
179 TRACE("Parsed %d sections and %d settings.\n", IniFileSectionCount
, IniFileSettingCount
);
180 TRACE("IniParseFile() done.\n");
185 ULONG
IniGetNextLineSize(PCHAR IniFileData
, ULONG IniFileSize
, ULONG CurrentOffset
)
187 ULONG LineCharCount
= 0;
189 // Loop through counting chars until we hit the end of the
190 // file or we encounter a new line char
191 for (; (CurrentOffset
< IniFileSize
); CurrentOffset
++)
193 // Increment the line character count
196 // Check for new line char
197 if (IniFileData
[CurrentOffset
] == '\n')
203 // Add one for the NULL-terminator
206 // Send back line character count
207 return LineCharCount
;
210 ULONG
IniGetNextLine(PCHAR IniFileData
, ULONG IniFileSize
, PCHAR Buffer
, ULONG BufferSize
, ULONG CurrentOffset
)
214 // Loop through grabbing chars until we hit the end of the
215 // file or we encounter a new line char
216 for (Idx
=0; (CurrentOffset
< IniFileSize
); CurrentOffset
++)
218 // If we haven't exceeded our buffer size yet
219 // then store another char
220 if (Idx
< (BufferSize
- 1))
222 Buffer
[Idx
++] = IniFileData
[CurrentOffset
];
225 // Check for new line char
226 if (IniFileData
[CurrentOffset
] == '\n')
233 // Terminate the string
236 // Get rid of newline & linefeed characters (if any)
237 while(Idx
&& (Buffer
[--Idx
] == '\n' || Buffer
[Idx
] == '\r'))
240 // Send back new offset
241 return CurrentOffset
;
244 BOOLEAN
IniIsLineEmpty(PCHAR LineOfText
, ULONG TextLength
)
248 // Check for text (skipping whitespace)
249 for (Idx
=0; Idx
<TextLength
; Idx
++)
251 if ((LineOfText
[Idx
] == ' ') ||
252 (LineOfText
[Idx
] == '\t') ||
253 (LineOfText
[Idx
] == '\n') ||
254 (LineOfText
[Idx
] == '\r'))
267 BOOLEAN
IniIsCommentLine(PCHAR LineOfText
, ULONG TextLength
)
271 // Check the first character (skipping whitespace)
272 // and make sure that it is an opening bracket
273 for (Idx
=0; Idx
<TextLength
; Idx
++)
275 if ((LineOfText
[Idx
] == ' ') ||
276 (LineOfText
[Idx
] == '\t'))
280 else if (LineOfText
[Idx
] == INI_FILE_COMMENT_CHAR
)
293 BOOLEAN
IniIsSectionName(PCHAR LineOfText
, ULONG TextLength
)
297 // Check the first character (skipping whitespace)
298 // and make sure that it is an opening bracket
299 for (Idx
=0; Idx
<TextLength
; Idx
++)
301 if ((LineOfText
[Idx
] == ' ') ||
302 (LineOfText
[Idx
] == '\t'))
306 else if (LineOfText
[Idx
] == '[')
319 ULONG
IniGetSectionNameSize(PCHAR SectionNameLine
, ULONG LineLength
)
324 // Find the opening bracket (skipping whitespace)
325 for (Idx
=0; Idx
<LineLength
; Idx
++)
327 if ((SectionNameLine
[Idx
] == ' ') ||
328 (SectionNameLine
[Idx
] == '\t'))
332 else //if (SectionNameLine[Idx] == '[')
338 // Skip past the opening bracket
341 // Count the characters up until the closing bracket or EOL
342 for (NameSize
=0; Idx
<LineLength
; Idx
++)
344 if ((SectionNameLine
[Idx
] == ']') ||
345 (SectionNameLine
[Idx
] == '\0'))
350 // Increment the count
354 // Add one for the NULL-terminator
360 VOID
IniExtractSectionName(PCHAR SectionName
, PCHAR SectionNameLine
, ULONG LineLength
)
365 // Find the opening bracket (skipping whitespace)
366 for (Idx
=0; Idx
<LineLength
; Idx
++)
368 if ((SectionNameLine
[Idx
] == ' ') ||
369 (SectionNameLine
[Idx
] == '\t'))
373 else //if (SectionNameLine[Idx] == '[')
379 // Skip past the opening bracket
382 // Count the characters up until the closing bracket or EOL
383 for (DestIdx
=0; Idx
<LineLength
; Idx
++)
385 if ((SectionNameLine
[Idx
] == ']') ||
386 (SectionNameLine
[Idx
] == '\0'))
391 // Grab a character and increment DestIdx
392 SectionName
[DestIdx
] = SectionNameLine
[Idx
];
396 // Terminate the string
397 SectionName
[DestIdx
] = '\0';
400 BOOLEAN
IniIsSetting(PCHAR LineOfText
, ULONG TextLength
)
404 // Basically just check for an '=' equals sign
405 for (Idx
=0; Idx
<TextLength
; Idx
++)
407 if (LineOfText
[Idx
] == '=')
416 ULONG
IniGetSettingNameSize(PCHAR SettingNameLine
, ULONG LineLength
)
422 for (Idx
=0; Idx
<LineLength
; Idx
++)
424 if ((SettingNameLine
[Idx
] == ' ') ||
425 (SettingNameLine
[Idx
] == '\t'))
435 // Count the characters up until the '=' equals sign or EOL
436 for (NameSize
=0; Idx
<LineLength
; Idx
++)
438 if ((SettingNameLine
[Idx
] == '=') ||
439 (SettingNameLine
[Idx
] == '\0'))
444 // Increment the count
448 // Add one for the NULL-terminator
454 ULONG
IniGetSettingValueSize(PCHAR SettingValueLine
, ULONG LineLength
)
460 for (Idx
=0; Idx
<LineLength
; Idx
++)
462 if ((SettingValueLine
[Idx
] == ' ') ||
463 (SettingValueLine
[Idx
] == '\t'))
473 // Skip the characters up until the '=' equals sign or EOL
474 for (; Idx
<LineLength
; Idx
++)
476 if (SettingValueLine
[Idx
] == '=')
482 // If we hit EOL then obviously the value size is zero
483 if (SettingValueLine
[Idx
] == '\0')
489 // Count the characters up until the EOL
490 for (ValueSize
=0; Idx
<LineLength
; Idx
++)
492 if (SettingValueLine
[Idx
] == '\0')
497 // Increment the count
501 // Add one for the NULL-terminator
507 VOID
IniExtractSettingName(PCHAR SettingName
, PCHAR SettingNameLine
, ULONG LineLength
)
513 for (Idx
=0; Idx
<LineLength
; Idx
++)
515 if ((SettingNameLine
[Idx
] == ' ') ||
516 (SettingNameLine
[Idx
] == '\t'))
526 // Get the characters up until the '=' equals sign or EOL
527 for (DestIdx
=0; Idx
<LineLength
; Idx
++)
529 if ((SettingNameLine
[Idx
] == '=') ||
530 (SettingNameLine
[Idx
] == '\0'))
535 // Grab a character and increment DestIdx
536 SettingName
[DestIdx
] = SettingNameLine
[Idx
];
540 // Terminate the string
541 SettingName
[DestIdx
] = '\0';
544 VOID
IniExtractSettingValue(PCHAR SettingValue
, PCHAR SettingValueLine
, ULONG LineLength
)
550 for (Idx
=0; Idx
<LineLength
; Idx
++)
552 if ((SettingValueLine
[Idx
] == ' ') ||
553 (SettingValueLine
[Idx
] == '\t'))
563 // Skip the characters up until the '=' equals sign or EOL
564 for (; Idx
<LineLength
; Idx
++)
566 if (SettingValueLine
[Idx
] == '=')
572 // If we hit EOL then obviously the value size is zero
573 if (SettingValueLine
[Idx
] == '\0')
575 SettingValue
[0] = '\0';
580 // Get the characters up until the EOL
581 for (DestIdx
=0; Idx
<LineLength
; Idx
++)
583 if (SettingValueLine
[Idx
] == '\0')
588 // Grab a character and increment DestIdx
589 SettingValue
[DestIdx
] = SettingValueLine
[Idx
];
593 // Terminate the string
594 SettingValue
[DestIdx
] = '\0';