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 LIST_ENTRY IniFileSectionListHead
;
24 BOOLEAN IniFileSectionInitialized
= FALSE
;
25 ULONG IniFileSectionCount
= 0;
26 ULONG IniFileSettingCount
= 0;
29 BOOLEAN
IniParseFile(PCHAR IniFileData
, ULONG IniFileSize
)
32 ULONG CurrentLineNumber
;
34 ULONG IniFileLineSize
;
36 PINI_SECTION CurrentSection
= NULL
;
37 PINI_SECTION_ITEM CurrentItem
= NULL
;
39 DPRINTM(DPRINT_INIFILE
, "IniParseFile() IniFileSize: %d\n", IniFileSize
);
41 if (!IniFileSectionInitialized
)
43 InitializeListHead(&IniFileSectionListHead
);
44 IniFileSectionInitialized
= TRUE
;
47 // Start with an 80-byte buffer
49 IniFileLine
= MmHeapAlloc(IniFileLineSize
);
55 // Loop through each line and parse it
56 CurrentLineNumber
= 0;
58 while (CurrentOffset
< IniFileSize
)
60 // First check the line size and increase our buffer if necessary
61 if (IniFileLineSize
< IniGetNextLineSize(IniFileData
, IniFileSize
, CurrentOffset
))
63 IniFileLineSize
= IniGetNextLineSize(IniFileData
, IniFileSize
, CurrentOffset
);
64 MmHeapFree(IniFileLine
);
65 IniFileLine
= MmHeapAlloc(IniFileLineSize
);
72 // Get the line of data
73 CurrentOffset
= IniGetNextLine(IniFileData
, IniFileSize
, IniFileLine
, IniFileLineSize
, CurrentOffset
);
74 LineLength
= strlen(IniFileLine
);
76 // If it is a blank line or a comment then skip it
77 if (IniIsLineEmpty(IniFileLine
, LineLength
) || IniIsCommentLine(IniFileLine
, LineLength
))
83 // Check if it is a new section
84 if (IniIsSectionName(IniFileLine
, LineLength
))
86 // Allocate a new section structure
87 CurrentSection
= MmHeapAlloc(sizeof(INI_SECTION
));
90 MmHeapFree(IniFileLine
);
94 RtlZeroMemory(CurrentSection
, sizeof(INI_SECTION
));
96 // Allocate the section name buffer
97 CurrentSection
->SectionName
= MmHeapAlloc(IniGetSectionNameSize(IniFileLine
, LineLength
));
98 if (!CurrentSection
->SectionName
)
100 MmHeapFree(CurrentSection
);
101 MmHeapFree(IniFileLine
);
105 // Get the section name
106 IniExtractSectionName(CurrentSection
->SectionName
, IniFileLine
, LineLength
);
107 InitializeListHead(&CurrentSection
->SectionItemList
);
109 // Add it to the section list head
110 IniFileSectionCount
++;
111 InsertTailList(&IniFileSectionListHead
, &CurrentSection
->ListEntry
);
117 // Check if it is a setting
118 if (IniIsSetting(IniFileLine
, LineLength
))
120 // First check to make sure we're inside a [section]
121 if (CurrentSection
== NULL
)
123 printf("Error: freeldr.ini:%ld: Setting '%s' found outside of a [section].\n", CurrentLineNumber
, IniFileLine
);
124 printf("Press any key to continue...\n");
130 // Allocate a new item structure
131 CurrentItem
= MmHeapAlloc(sizeof(INI_SECTION_ITEM
));
134 MmHeapFree(IniFileLine
);
138 RtlZeroMemory(CurrentItem
, sizeof(INI_SECTION_ITEM
));
140 // Allocate the setting name buffer
141 CurrentItem
->ItemName
= MmHeapAlloc(IniGetSettingNameSize(IniFileLine
, LineLength
));
142 if (!CurrentItem
->ItemName
)
144 MmHeapFree(CurrentItem
);
145 MmHeapFree(IniFileLine
);
149 // Allocate the setting value buffer
150 CurrentItem
->ItemValue
= MmHeapAlloc(IniGetSettingValueSize(IniFileLine
, LineLength
));
151 if (!CurrentItem
->ItemValue
)
153 MmHeapFree(CurrentItem
->ItemName
);
154 MmHeapFree(CurrentItem
);
155 MmHeapFree(IniFileLine
);
159 // Get the section name
160 IniExtractSettingName(CurrentItem
->ItemName
, IniFileLine
, LineLength
);
161 IniExtractSettingValue(CurrentItem
->ItemValue
, IniFileLine
, LineLength
);
163 // Add it to the current section
164 IniFileSettingCount
++;
165 CurrentSection
->SectionItemCount
++;
166 InsertTailList(&CurrentSection
->SectionItemList
, &CurrentItem
->ListEntry
);
175 DPRINTM(DPRINT_INIFILE
, "Parsed %d sections and %d settings.\n", IniFileSectionCount
, IniFileSettingCount
);
176 DPRINTM(DPRINT_INIFILE
, "IniParseFile() done.\n");
181 ULONG
IniGetNextLineSize(PCHAR IniFileData
, ULONG IniFileSize
, ULONG CurrentOffset
)
184 ULONG LineCharCount
= 0;
186 // Loop through counting chars until we hit the end of the
187 // file or we encounter a new line char
188 for (Idx
=0; (CurrentOffset
< IniFileSize
); CurrentOffset
++)
190 // Increment the line character count
193 // Check for new line char
194 if (IniFileData
[CurrentOffset
] == '\n')
201 // Add one for the NULL-terminator
204 // Send back line character count
205 return LineCharCount
;
208 ULONG
IniGetNextLine(PCHAR IniFileData
, ULONG IniFileSize
, PCHAR Buffer
, ULONG BufferSize
, ULONG CurrentOffset
)
212 // Loop through grabbing chars until we hit the end of the
213 // file or we encounter a new line char
214 for (Idx
=0; (CurrentOffset
< IniFileSize
); CurrentOffset
++)
216 // If we haven't exceeded our buffer size yet
217 // then store another char
218 if (Idx
< (BufferSize
- 1))
220 Buffer
[Idx
++] = IniFileData
[CurrentOffset
];
223 // Check for new line char
224 if (IniFileData
[CurrentOffset
] == '\n')
231 // Terminate the string
234 // Get rid of newline & linefeed characters (if any)
235 while(Idx
&& (Buffer
[--Idx
] == '\n' || Buffer
[Idx
] == '\r'))
238 // Send back new offset
239 return CurrentOffset
;
242 BOOLEAN
IniIsLineEmpty(PCHAR LineOfText
, ULONG TextLength
)
246 // Check for text (skipping whitespace)
247 for (Idx
=0; Idx
<TextLength
; Idx
++)
249 if ((LineOfText
[Idx
] == ' ') ||
250 (LineOfText
[Idx
] == '\t') ||
251 (LineOfText
[Idx
] == '\n') ||
252 (LineOfText
[Idx
] == '\r'))
265 BOOLEAN
IniIsCommentLine(PCHAR LineOfText
, ULONG TextLength
)
269 // Check the first character (skipping whitespace)
270 // and make sure that it is an opening bracket
271 for (Idx
=0; Idx
<TextLength
; Idx
++)
273 if ((LineOfText
[Idx
] == ' ') ||
274 (LineOfText
[Idx
] == '\t'))
278 else if (LineOfText
[Idx
] == INI_FILE_COMMENT_CHAR
)
291 BOOLEAN
IniIsSectionName(PCHAR LineOfText
, ULONG TextLength
)
295 // Check the first character (skipping whitespace)
296 // and make sure that it is an opening bracket
297 for (Idx
=0; Idx
<TextLength
; Idx
++)
299 if ((LineOfText
[Idx
] == ' ') ||
300 (LineOfText
[Idx
] == '\t'))
304 else if (LineOfText
[Idx
] == '[')
317 ULONG
IniGetSectionNameSize(PCHAR SectionNameLine
, ULONG LineLength
)
322 // Find the opening bracket (skipping whitespace)
323 for (Idx
=0; Idx
<LineLength
; Idx
++)
325 if ((SectionNameLine
[Idx
] == ' ') ||
326 (SectionNameLine
[Idx
] == '\t'))
330 else //if (SectionNameLine[Idx] == '[')
336 // Skip past the opening bracket
339 // Count the characters up until the closing bracket or EOL
340 for (NameSize
=0; Idx
<LineLength
; Idx
++)
342 if ((SectionNameLine
[Idx
] == ']') ||
343 (SectionNameLine
[Idx
] == '\0'))
348 // Increment the count
352 // Add one for the NULL-terminator
358 VOID
IniExtractSectionName(PCHAR SectionName
, PCHAR SectionNameLine
, ULONG LineLength
)
363 // Find the opening bracket (skipping whitespace)
364 for (Idx
=0; Idx
<LineLength
; Idx
++)
366 if ((SectionNameLine
[Idx
] == ' ') ||
367 (SectionNameLine
[Idx
] == '\t'))
371 else //if (SectionNameLine[Idx] == '[')
377 // Skip past the opening bracket
380 // Count the characters up until the closing bracket or EOL
381 for (DestIdx
=0; Idx
<LineLength
; Idx
++)
383 if ((SectionNameLine
[Idx
] == ']') ||
384 (SectionNameLine
[Idx
] == '\0'))
389 // Grab a character and increment DestIdx
390 SectionName
[DestIdx
] = SectionNameLine
[Idx
];
394 // Terminate the string
395 SectionName
[DestIdx
] = '\0';
398 BOOLEAN
IniIsSetting(PCHAR LineOfText
, ULONG TextLength
)
402 // Basically just check for an '=' equals sign
403 for (Idx
=0; Idx
<TextLength
; Idx
++)
405 if (LineOfText
[Idx
] == '=')
414 ULONG
IniGetSettingNameSize(PCHAR SettingNameLine
, ULONG LineLength
)
420 for (Idx
=0; Idx
<LineLength
; Idx
++)
422 if ((SettingNameLine
[Idx
] == ' ') ||
423 (SettingNameLine
[Idx
] == '\t'))
433 // Count the characters up until the '=' equals sign or EOL
434 for (NameSize
=0; Idx
<LineLength
; Idx
++)
436 if ((SettingNameLine
[Idx
] == '=') ||
437 (SettingNameLine
[Idx
] == '\0'))
442 // Increment the count
446 // Add one for the NULL-terminator
452 ULONG
IniGetSettingValueSize(PCHAR SettingValueLine
, ULONG LineLength
)
458 for (Idx
=0; Idx
<LineLength
; Idx
++)
460 if ((SettingValueLine
[Idx
] == ' ') ||
461 (SettingValueLine
[Idx
] == '\t'))
471 // Skip the characters up until the '=' equals sign or EOL
472 for (; Idx
<LineLength
; Idx
++)
474 if (SettingValueLine
[Idx
] == '=')
480 // If we hit EOL then obviously the value size is zero
481 if (SettingValueLine
[Idx
] == '\0')
487 // Count the characters up until the EOL
488 for (ValueSize
=0; Idx
<LineLength
; Idx
++)
490 if (SettingValueLine
[Idx
] == '\0')
495 // Increment the count
499 // Add one for the NULL-terminator
505 VOID
IniExtractSettingName(PCHAR SettingName
, PCHAR SettingNameLine
, ULONG LineLength
)
511 for (Idx
=0; Idx
<LineLength
; Idx
++)
513 if ((SettingNameLine
[Idx
] == ' ') ||
514 (SettingNameLine
[Idx
] == '\t'))
524 // Get the characters up until the '=' equals sign or EOL
525 for (DestIdx
=0; Idx
<LineLength
; Idx
++)
527 if ((SettingNameLine
[Idx
] == '=') ||
528 (SettingNameLine
[Idx
] == '\0'))
533 // Grab a character and increment DestIdx
534 SettingName
[DestIdx
] = SettingNameLine
[Idx
];
538 // Terminate the string
539 SettingName
[DestIdx
] = '\0';
542 VOID
IniExtractSettingValue(PCHAR SettingValue
, PCHAR SettingValueLine
, ULONG LineLength
)
548 for (Idx
=0; Idx
<LineLength
; Idx
++)
550 if ((SettingValueLine
[Idx
] == ' ') ||
551 (SettingValueLine
[Idx
] == '\t'))
561 // Skip the characters up until the '=' equals sign or EOL
562 for (; Idx
<LineLength
; Idx
++)
564 if (SettingValueLine
[Idx
] == '=')
570 // If we hit EOL then obviously the value size is zero
571 if (SettingValueLine
[Idx
] == '\0')
573 SettingValue
[0] = '\0';
578 // Get the characters up until the EOL
579 for (DestIdx
=0; Idx
<LineLength
; Idx
++)
581 if (SettingValueLine
[Idx
] == '\0')
586 // Grab a character and increment DestIdx
587 SettingValue
[DestIdx
] = SettingValueLine
[Idx
];
591 // Terminate the string
592 SettingValue
[DestIdx
] = '\0';