For some strange reason IniFileSectionListHead is not initialized correctly.
[reactos.git] / freeldr / freeldr / inifile / parse.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <freeldr.h>
21 #include "ini.h"
22 #include <rtl.h>
23 #include <mm.h>
24 #include <debug.h>
25
26
27 PINI_SECTION IniFileSectionListHead = NULL;
28 U32 IniFileSectionCount = 0;
29 U32 IniFileSettingCount = 0;
30
31
32 BOOL IniParseFile(PUCHAR IniFileData, U32 IniFileSize)
33 {
34 U32 CurrentOffset;
35 U32 CurrentLineNumber;
36 PUCHAR IniFileLine;
37 U32 IniFileLineSize;
38 U32 LineLength;
39 PINI_SECTION CurrentSection = NULL;
40 PINI_SECTION_ITEM CurrentItem = NULL;
41
42 DbgPrint((DPRINT_INIFILE, "IniParseFile() IniFileSize: %d\n", IniFileSize));
43
44 IniFileSectionListHead = NULL;
45 IniFileSectionCount = 0;
46 IniFileSettingCount = 0;
47
48 // Start with an 80-byte buffer
49 IniFileLineSize = 80;
50 IniFileLine = MmAllocateMemory(IniFileLineSize);
51 if (!IniFileLine)
52 {
53 return FALSE;
54 }
55
56 // Loop through each line and parse it
57 CurrentLineNumber = 0;
58 CurrentOffset = 0;
59 while (CurrentOffset < IniFileSize)
60 {
61 // First check the line size and increase our buffer if necessary
62 if (IniFileLineSize < IniGetNextLineSize(IniFileData, IniFileSize, CurrentOffset))
63 {
64 IniFileLineSize = IniGetNextLineSize(IniFileData, IniFileSize, CurrentOffset);
65 MmFreeMemory(IniFileLine);
66 IniFileLine = MmAllocateMemory(IniFileLineSize);
67 if (!IniFileLine)
68 {
69 return FALSE;
70 }
71 }
72
73 // Get the line of data
74 CurrentOffset = IniGetNextLine(IniFileData, IniFileSize, IniFileLine, IniFileLineSize, CurrentOffset);
75 LineLength = strlen(IniFileLine);
76
77 // If it is a blank line or a comment then skip it
78 if (IniIsLineEmpty(IniFileLine, LineLength) || IniIsCommentLine(IniFileLine, LineLength))
79 {
80 CurrentLineNumber++;
81 continue;
82 }
83
84 // Check if it is a new section
85 if (IniIsSectionName(IniFileLine, LineLength))
86 {
87 // Allocate a new section structure
88 CurrentSection = MmAllocateMemory(sizeof(INI_SECTION));
89 if (!CurrentSection)
90 {
91 MmFreeMemory(IniFileLine);
92 return FALSE;
93 }
94
95 RtlZeroMemory(CurrentSection, sizeof(INI_SECTION));
96
97 // Allocate the section name buffer
98 CurrentSection->SectionName = MmAllocateMemory(IniGetSectionNameSize(IniFileLine, LineLength));
99 if (!CurrentSection->SectionName)
100 {
101 MmFreeMemory(CurrentSection);
102 MmFreeMemory(IniFileLine);
103 return FALSE;
104 }
105
106 // Get the section name
107 IniExtractSectionName(CurrentSection->SectionName, IniFileLine, LineLength);
108
109 // Add it to the section list head
110 IniFileSectionCount++;
111 if (IniFileSectionListHead == NULL)
112 {
113 IniFileSectionListHead = CurrentSection;
114 }
115 else
116 {
117 RtlListInsertTail((PLIST_ITEM)IniFileSectionListHead, (PLIST_ITEM)CurrentSection);
118 }
119
120 CurrentLineNumber++;
121 continue;
122 }
123
124 // Check if it is a setting
125 if (IniIsSetting(IniFileLine, LineLength))
126 {
127 // First check to make sure we're inside a [section]
128 if (CurrentSection == NULL)
129 {
130 printf("Error: freeldr.ini:%ld: Setting '%s' found outside of a [section].\n", CurrentLineNumber, IniFileLine);
131 printf("Press any key to continue...\n");
132 getch();
133 CurrentLineNumber++;
134 continue;
135 }
136
137 // Allocate a new item structure
138 CurrentItem = MmAllocateMemory(sizeof(INI_SECTION_ITEM));
139 if (!CurrentItem)
140 {
141 MmFreeMemory(IniFileLine);
142 return FALSE;
143 }
144
145 RtlZeroMemory(CurrentItem, sizeof(INI_SECTION_ITEM));
146
147 // Allocate the setting name buffer
148 CurrentItem->ItemName = MmAllocateMemory(IniGetSettingNameSize(IniFileLine, LineLength));
149 if (!CurrentItem->ItemName)
150 {
151 MmFreeMemory(CurrentItem);
152 MmFreeMemory(IniFileLine);
153 return FALSE;
154 }
155
156 // Allocate the setting value buffer
157 CurrentItem->ItemValue = MmAllocateMemory(IniGetSettingValueSize(IniFileLine, LineLength));
158 if (!CurrentItem->ItemValue)
159 {
160 MmFreeMemory(CurrentItem->ItemName);
161 MmFreeMemory(CurrentItem);
162 MmFreeMemory(IniFileLine);
163 return FALSE;
164 }
165
166 // Get the section name
167 IniExtractSettingName(CurrentItem->ItemName, IniFileLine, LineLength);
168 IniExtractSettingValue(CurrentItem->ItemValue, IniFileLine, LineLength);
169
170 // Add it to the current section
171 IniFileSettingCount++;
172 CurrentSection->SectionItemCount++;
173 if (CurrentSection->SectionItemList == NULL)
174 {
175 CurrentSection->SectionItemList = CurrentItem;
176 }
177 else
178 {
179 RtlListInsertTail((PLIST_ITEM)CurrentSection->SectionItemList, (PLIST_ITEM)CurrentItem);
180 }
181
182 CurrentLineNumber++;
183 continue;
184 }
185
186 CurrentLineNumber++;
187 }
188
189 DbgPrint((DPRINT_INIFILE, "Parsed %d sections and %d settings.\n", IniFileSectionCount, IniFileSettingCount));
190 DbgPrint((DPRINT_INIFILE, "IniParseFile() done.\n"));
191
192 return TRUE;
193 }
194
195 U32 IniGetNextLineSize(PUCHAR IniFileData, U32 IniFileSize, U32 CurrentOffset)
196 {
197 U32 Idx;
198 U32 LineCharCount = 0;
199
200 // Loop through counting chars until we hit the end of the
201 // file or we encounter a new line char
202 for (Idx=0; (CurrentOffset < IniFileSize); CurrentOffset++)
203 {
204 // Increment the line character count
205 LineCharCount++;
206
207 // Check for new line char
208 if (IniFileData[CurrentOffset] == '\n')
209 {
210 CurrentOffset++;
211 break;
212 }
213 }
214
215 // Add one for the NULL-terminator
216 LineCharCount++;
217
218 // Send back line character count
219 return LineCharCount;
220 }
221
222 U32 IniGetNextLine(PUCHAR IniFileData, U32 IniFileSize, PUCHAR Buffer, U32 BufferSize, U32 CurrentOffset)
223 {
224 U32 Idx;
225
226 // Loop through grabbing chars until we hit the end of the
227 // file or we encounter a new line char
228 for (Idx=0; (CurrentOffset < IniFileSize); CurrentOffset++)
229 {
230 // If we haven't exceeded our buffer size yet
231 // then store another char
232 if (Idx < (BufferSize - 1))
233 {
234 Buffer[Idx++] = IniFileData[CurrentOffset];
235 }
236
237 // Check for new line char
238 if (IniFileData[CurrentOffset] == '\n')
239 {
240 CurrentOffset++;
241 break;
242 }
243 }
244
245 // Terminate the string
246 Buffer[Idx] = '\0';
247
248 // Get rid of newline & linefeed characters (if any)
249 if((Buffer[strlen(Buffer)-1] == '\n') || (Buffer[strlen(Buffer)-1] == '\r'))
250 Buffer[strlen(Buffer)-1] = '\0';
251 if((Buffer[strlen(Buffer)-1] == '\n') || (Buffer[strlen(Buffer)-1] == '\r'))
252 Buffer[strlen(Buffer)-1] = '\0';
253
254 // Send back new offset
255 return CurrentOffset;
256 }
257
258 BOOL IniIsLineEmpty(PUCHAR LineOfText, U32 TextLength)
259 {
260 U32 Idx;
261
262 // Check for text (skipping whitespace)
263 for (Idx=0; Idx<TextLength; Idx++)
264 {
265 if ((LineOfText[Idx] == ' ') ||
266 (LineOfText[Idx] == '\t') ||
267 (LineOfText[Idx] == '\n') ||
268 (LineOfText[Idx] == '\r'))
269 {
270 continue;
271 }
272 else
273 {
274 return FALSE;
275 }
276 }
277
278 return TRUE;
279 }
280
281 BOOL IniIsCommentLine(PUCHAR LineOfText, U32 TextLength)
282 {
283 U32 Idx;
284
285 // Check the first character (skipping whitespace)
286 // and make sure that it is an opening bracket
287 for (Idx=0; Idx<TextLength; Idx++)
288 {
289 if ((LineOfText[Idx] == ' ') ||
290 (LineOfText[Idx] == '\t'))
291 {
292 continue;
293 }
294 else if (LineOfText[Idx] == INI_FILE_COMMENT_CHAR)
295 {
296 return TRUE;
297 }
298 else
299 {
300 break;
301 }
302 }
303
304 return FALSE;
305 }
306
307 BOOL IniIsSectionName(PUCHAR LineOfText, U32 TextLength)
308 {
309 U32 Idx;
310
311 // Check the first character (skipping whitespace)
312 // and make sure that it is an opening bracket
313 for (Idx=0; Idx<TextLength; Idx++)
314 {
315 if ((LineOfText[Idx] == ' ') ||
316 (LineOfText[Idx] == '\t'))
317 {
318 continue;
319 }
320 else if (LineOfText[Idx] == '[')
321 {
322 return TRUE;
323 }
324 else
325 {
326 break;
327 }
328 }
329
330 return FALSE;
331 }
332
333 U32 IniGetSectionNameSize(PUCHAR SectionNameLine, U32 LineLength)
334 {
335 U32 Idx;
336 U32 NameSize;
337
338 // Find the opening bracket (skipping whitespace)
339 for (Idx=0; Idx<LineLength; Idx++)
340 {
341 if ((SectionNameLine[Idx] == ' ') ||
342 (SectionNameLine[Idx] == '\t'))
343 {
344 continue;
345 }
346 else //if (SectionNameLine[Idx] == '[')
347 {
348 break;
349 }
350 }
351
352 // Skip past the opening bracket
353 Idx++;
354
355 // Count the characters up until the closing bracket or EOL
356 for (NameSize=0; Idx<LineLength; Idx++)
357 {
358 if ((SectionNameLine[Idx] == ']') ||
359 (SectionNameLine[Idx] == '\0'))
360 {
361 break;
362 }
363
364 // Increment the count
365 NameSize++;
366 }
367
368 // Add one for the NULL-terminator
369 NameSize++;
370
371 return NameSize;
372 }
373
374 VOID IniExtractSectionName(PUCHAR SectionName, PUCHAR SectionNameLine, U32 LineLength)
375 {
376 U32 Idx;
377 U32 DestIdx;
378
379 // Find the opening bracket (skipping whitespace)
380 for (Idx=0; Idx<LineLength; Idx++)
381 {
382 if ((SectionNameLine[Idx] == ' ') ||
383 (SectionNameLine[Idx] == '\t'))
384 {
385 continue;
386 }
387 else //if (SectionNameLine[Idx] == '[')
388 {
389 break;
390 }
391 }
392
393 // Skip past the opening bracket
394 Idx++;
395
396 // Count the characters up until the closing bracket or EOL
397 for (DestIdx=0; Idx<LineLength; Idx++)
398 {
399 if ((SectionNameLine[Idx] == ']') ||
400 (SectionNameLine[Idx] == '\0'))
401 {
402 break;
403 }
404
405 // Grab a character and increment DestIdx
406 SectionName[DestIdx] = SectionNameLine[Idx];
407 DestIdx++;
408 }
409
410 // Terminate the string
411 SectionName[DestIdx] = '\0';
412 }
413
414 BOOL IniIsSetting(PUCHAR LineOfText, U32 TextLength)
415 {
416 U32 Idx;
417
418 // Basically just check for an '=' equals sign
419 for (Idx=0; Idx<TextLength; Idx++)
420 {
421 if (LineOfText[Idx] == '=')
422 {
423 return TRUE;
424 }
425 }
426
427 return FALSE;
428 }
429
430 U32 IniGetSettingNameSize(PUCHAR SettingNameLine, U32 LineLength)
431 {
432 U32 Idx;
433 U32 NameSize;
434
435 // Skip whitespace
436 for (Idx=0; Idx<LineLength; Idx++)
437 {
438 if ((SettingNameLine[Idx] == ' ') ||
439 (SettingNameLine[Idx] == '\t'))
440 {
441 continue;
442 }
443 else
444 {
445 break;
446 }
447 }
448
449 // Count the characters up until the '=' equals sign or EOL
450 for (NameSize=0; Idx<LineLength; Idx++)
451 {
452 if ((SettingNameLine[Idx] == '=') ||
453 (SettingNameLine[Idx] == '\0'))
454 {
455 break;
456 }
457
458 // Increment the count
459 NameSize++;
460 }
461
462 // Add one for the NULL-terminator
463 NameSize++;
464
465 return NameSize;
466 }
467
468 U32 IniGetSettingValueSize(PUCHAR SettingValueLine, U32 LineLength)
469 {
470 U32 Idx;
471 U32 ValueSize;
472
473 // Skip whitespace
474 for (Idx=0; Idx<LineLength; Idx++)
475 {
476 if ((SettingValueLine[Idx] == ' ') ||
477 (SettingValueLine[Idx] == '\t'))
478 {
479 continue;
480 }
481 else
482 {
483 break;
484 }
485 }
486
487 // Skip the characters up until the '=' equals sign or EOL
488 for (; Idx<LineLength; Idx++)
489 {
490 if (SettingValueLine[Idx] == '=')
491 {
492 Idx++;
493 break;
494 }
495
496 // If we hit EOL then obviously the value size is zero
497 if (SettingValueLine[Idx] == '\0')
498 {
499 return 0;
500 }
501 }
502
503 // Count the characters up until the EOL
504 for (ValueSize=0; Idx<LineLength; Idx++)
505 {
506 if (SettingValueLine[Idx] == '\0')
507 {
508 break;
509 }
510
511 // Increment the count
512 ValueSize++;
513 }
514
515 // Add one for the NULL-terminator
516 ValueSize++;
517
518 return ValueSize;
519 }
520
521 VOID IniExtractSettingName(PUCHAR SettingName, PUCHAR SettingNameLine, U32 LineLength)
522 {
523 U32 Idx;
524 U32 DestIdx;
525
526 // Skip whitespace
527 for (Idx=0; Idx<LineLength; Idx++)
528 {
529 if ((SettingNameLine[Idx] == ' ') ||
530 (SettingNameLine[Idx] == '\t'))
531 {
532 continue;
533 }
534 else
535 {
536 break;
537 }
538 }
539
540 // Get the characters up until the '=' equals sign or EOL
541 for (DestIdx=0; Idx<LineLength; Idx++)
542 {
543 if ((SettingNameLine[Idx] == '=') ||
544 (SettingNameLine[Idx] == '\0'))
545 {
546 break;
547 }
548
549 // Grab a character and increment DestIdx
550 SettingName[DestIdx] = SettingNameLine[Idx];
551 DestIdx++;
552 }
553
554 // Terminate the string
555 SettingName[DestIdx] = '\0';
556 }
557
558 VOID IniExtractSettingValue(PUCHAR SettingValue, PUCHAR SettingValueLine, U32 LineLength)
559 {
560 U32 Idx;
561 U32 DestIdx;
562
563 // Skip whitespace
564 for (Idx=0; Idx<LineLength; Idx++)
565 {
566 if ((SettingValueLine[Idx] == ' ') ||
567 (SettingValueLine[Idx] == '\t'))
568 {
569 continue;
570 }
571 else
572 {
573 break;
574 }
575 }
576
577 // Skip the characters up until the '=' equals sign or EOL
578 for (; Idx<LineLength; Idx++)
579 {
580 if (SettingValueLine[Idx] == '=')
581 {
582 Idx++;
583 break;
584 }
585
586 // If we hit EOL then obviously the value size is zero
587 if (SettingValueLine[Idx] == '\0')
588 {
589 SettingValue[0] = '\0';
590 return;
591 }
592 }
593
594 // Get the characters up until the EOL
595 for (DestIdx=0; Idx<LineLength; Idx++)
596 {
597 if (SettingValueLine[Idx] == '\0')
598 {
599 break;
600 }
601
602 // Grab a character and increment DestIdx
603 SettingValue[DestIdx] = SettingValueLine[Idx];
604 DestIdx++;
605 }
606
607 // Terminate the string
608 SettingValue[DestIdx] = '\0';
609 }