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