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