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