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
;
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
= MmHeapAlloc(IniFileLineSize
);
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 MmHeapFree(IniFileLine
);
67 IniFileLine
= MmHeapAlloc(IniFileLineSize
);
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
= MmHeapAlloc(sizeof(INI_SECTION
));
92 MmHeapFree(IniFileLine
);
96 RtlZeroMemory(CurrentSection
, sizeof(INI_SECTION
));
98 // Allocate the section name buffer
99 CurrentSection
->SectionName
= MmHeapAlloc(IniGetSectionNameSize(IniFileLine
, LineLength
));
100 if (!CurrentSection
->SectionName
)
102 MmHeapFree(CurrentSection
);
103 MmHeapFree(IniFileLine
);
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 printf("Error: freeldr.ini:%ld: Setting '%s' found outside of a [section].\n", CurrentLineNumber
, IniFileLine
);
126 printf("Press any key to continue...\n");
132 // Allocate a new item structure
133 CurrentItem
= MmHeapAlloc(sizeof(INI_SECTION_ITEM
));
136 MmHeapFree(IniFileLine
);
140 RtlZeroMemory(CurrentItem
, sizeof(INI_SECTION_ITEM
));
142 // Allocate the setting name buffer
143 CurrentItem
->ItemName
= MmHeapAlloc(IniGetSettingNameSize(IniFileLine
, LineLength
));
144 if (!CurrentItem
->ItemName
)
146 MmHeapFree(CurrentItem
);
147 MmHeapFree(IniFileLine
);
151 // Allocate the setting value buffer
152 CurrentItem
->ItemValue
= MmHeapAlloc(IniGetSettingValueSize(IniFileLine
, LineLength
));
153 if (!CurrentItem
->ItemValue
)
155 MmHeapFree(CurrentItem
->ItemName
);
156 MmHeapFree(CurrentItem
);
157 MmHeapFree(IniFileLine
);
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 TRACE("Parsed %d sections and %d settings.\n", IniFileSectionCount
, IniFileSettingCount
);
178 TRACE("IniParseFile() done.\n");
183 ULONG
IniGetNextLineSize(PCHAR IniFileData
, ULONG IniFileSize
, ULONG CurrentOffset
)
185 ULONG LineCharCount
= 0;
187 // Loop through counting chars until we hit the end of the
188 // file or we encounter a new line char
189 for (; (CurrentOffset
< IniFileSize
); CurrentOffset
++)
191 // Increment the line character count
194 // Check for new line char
195 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';