VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartCfg.cpp@ 53426

Last change on this file since 53426 was 46737, checked in by vboxsync, 12 years ago

FE/VBoxAutostart: Todos and comments

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/* $Id: VBoxAutostartCfg.cpp 46737 2013-06-23 12:11:45Z vboxsync $ */
2/** @file
3 * VBoxAutostart - VirtualBox Autostart service, configuration parser.
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21
22#include <iprt/stream.h>
23#include <iprt/process.h>
24#include <iprt/string.h>
25#include <iprt/mem.h>
26#include <iprt/ctype.h>
27#include <iprt/message.h>
28
29#include "VBoxAutostart.h"
30
31/*******************************************************************************
32* Constants And Macros, Structures and Typedefs *
33*******************************************************************************/
34
35/**
36 * Token type.
37 */
38typedef enum CFGTOKENTYPE
39{
40 /** Invalid token type. */
41 CFGTOKENTYPE_INVALID = 0,
42 /** Identifier. */
43 CFGTOKENTYPE_ID,
44 /** Comma. */
45 CFGTOKENTYPE_COMMA,
46 /** Equal sign. */
47 CFGTOKENTYPE_EQUAL,
48 /** Open curly brackets. */
49 CFGTOKENTYPE_CURLY_OPEN,
50 /** Closing curly brackets. */
51 CFGTOKENTYPE_CURLY_CLOSING,
52 /** End of file. */
53 CFGTOKENTYPE_EOF,
54 /** 32bit hack. */
55 CFGTOKENTYPE_32BIT_HACK = 0x7fffffff
56} CFGTOKENTYPE;
57/** Pointer to a token type. */
58typedef CFGTOKENTYPE *PCFGTOKENTYPE;
59/** Pointer to a const token type. */
60typedef const CFGTOKENTYPE *PCCFGTOKENTYPE;
61
62/**
63 * A token.
64 */
65typedef struct CFGTOKEN
66{
67 /** Type of the token. */
68 CFGTOKENTYPE enmType;
69 /** Line number of the token. */
70 unsigned iLine;
71 /** Starting character of the token in the stream. */
72 unsigned cchStart;
73 /** Type dependen token data. */
74 union
75 {
76 /** Data for the ID type. */
77 struct
78 {
79 /** Size of the id in characters, excluding the \0 terminator. */
80 size_t cchToken;
81 /** Token data, variable size (given by cchToken member). */
82 char achToken[1];
83 } Id;
84 } u;
85} CFGTOKEN;
86/** Pointer to a token. */
87typedef CFGTOKEN *PCFGTOKEN;
88/** Pointer to a const token. */
89typedef const CFGTOKEN *PCCFGTOKEN;
90
91/**
92 * Tokenizer instance data for the config data.
93 */
94typedef struct CFGTOKENIZER
95{
96 /** Config file handle. */
97 PRTSTREAM hStrmConfig;
98 /** String buffer for the current line we are operating in. */
99 char *pszLine;
100 /** Size of the string buffer. */
101 size_t cbLine;
102 /** Current position in the line. */
103 char *pszLineCurr;
104 /** Current line in the config file. */
105 unsigned iLine;
106 /** Current character of the line. */
107 unsigned cchCurr;
108 /** Flag whether the end of the config stream is reached. */
109 bool fEof;
110 /** Pointer to the next token in the stream (used to peek). */
111 PCFGTOKEN pTokenNext;
112} CFGTOKENIZER, *PCFGTOKENIZER;
113
114/*******************************************************************************
115* Internal Functions *
116*******************************************************************************/
117
118/**
119 * Free a config token.
120 *
121 * @returns nothing.
122 * @param pCfgTokenizer The config tokenizer.
123 * @param pToken The token to free.
124 */
125static void autostartConfigTokenFree(PCFGTOKENIZER pCfgTokenizer, PCFGTOKEN pToken)
126{
127 NOREF(pCfgTokenizer);
128 RTMemFree(pToken);
129}
130
131/**
132 * Reads the next line from the config stream.
133 *
134 * @returns VBox status code.
135 * @param pCfgTokenizer The config tokenizer.
136 */
137static int autostartConfigTokenizerReadNextLine(PCFGTOKENIZER pCfgTokenizer)
138{
139 int rc = VINF_SUCCESS;
140
141 if (pCfgTokenizer->fEof)
142 return VERR_EOF;
143
144 do
145 {
146 rc = RTStrmGetLine(pCfgTokenizer->hStrmConfig, pCfgTokenizer->pszLine,
147 pCfgTokenizer->cbLine);
148 if (rc == VERR_BUFFER_OVERFLOW)
149 {
150 char *pszTmp;
151
152 pCfgTokenizer->cbLine += 128;
153 pszTmp = (char *)RTMemRealloc(pCfgTokenizer->pszLine, pCfgTokenizer->cbLine);
154 if (pszTmp)
155 pCfgTokenizer->pszLine = pszTmp;
156 else
157 rc = VERR_NO_MEMORY;
158 }
159 } while (rc == VERR_BUFFER_OVERFLOW);
160
161 if ( RT_SUCCESS(rc)
162 || rc == VERR_EOF)
163 {
164 pCfgTokenizer->iLine++;
165 pCfgTokenizer->cchCurr = 1;
166 pCfgTokenizer->pszLineCurr = pCfgTokenizer->pszLine;
167 if (rc == VERR_EOF)
168 pCfgTokenizer->fEof = true;
169 }
170
171 return rc;
172}
173
174/**
175 * Get the next token from the config stream and create a token structure.
176 *
177 * @returns VBox status code.
178 * @param pCfgTokenizer The config tokenizer data.
179 * @param pCfgTokenUse Allocated token structure to use or NULL to allocate
180 * a new one. It will bee freed if an error is encountered.
181 * @param ppCfgToken Where to store the pointer to the next token on success.
182 */
183static int autostartConfigTokenizerCreateToken(PCFGTOKENIZER pCfgTokenizer,
184 PCFGTOKEN pCfgTokenUse, PCFGTOKEN *ppCfgToken)
185{
186 const char *pszToken = NULL;
187 size_t cchToken = 1;
188 size_t cchAdvance = 0;
189 CFGTOKENTYPE enmType = CFGTOKENTYPE_INVALID;
190 int rc = VINF_SUCCESS;
191
192 for (;;)
193 {
194 pszToken = pCfgTokenizer->pszLineCurr;
195
196 /* Skip all spaces. */
197 while (RT_C_IS_BLANK(*pszToken))
198 {
199 pszToken++;
200 cchAdvance++;
201 }
202
203 /* Check if we have to read a new line. */
204 if ( *pszToken == '\0'
205 || *pszToken == '#')
206 {
207 rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer);
208 if (rc == VERR_EOF)
209 {
210 enmType = CFGTOKENTYPE_EOF;
211 rc = VINF_SUCCESS;
212 break;
213 }
214 else if (RT_FAILURE(rc))
215 break;
216 /* start from the beginning. */
217 cchAdvance = 0;
218 }
219 else if (*pszToken == '=')
220 {
221 enmType = CFGTOKENTYPE_EQUAL;
222 break;
223 }
224 else if (*pszToken == ',')
225 {
226 enmType = CFGTOKENTYPE_COMMA;
227 break;
228 }
229 else if (*pszToken == '{')
230 {
231 enmType = CFGTOKENTYPE_CURLY_OPEN;
232 break;
233 }
234 else if (*pszToken == '}')
235 {
236 enmType = CFGTOKENTYPE_CURLY_CLOSING;
237 break;
238 }
239 else
240 {
241 const char *pszTmp = pszToken;
242 cchToken = 0;
243 enmType = CFGTOKENTYPE_ID;
244
245 /* Get the complete token. */
246 while ( RT_C_IS_ALNUM(*pszTmp)
247 || *pszTmp == '_'
248 || *pszTmp == '.')
249 {
250 pszTmp++;
251 cchToken++;
252 }
253 break;
254 }
255 }
256
257 Assert(RT_FAILURE(rc) || enmType != CFGTOKENTYPE_INVALID);
258
259 if (RT_SUCCESS(rc))
260 {
261 /* Free the given token if it is an ID or the current one is an ID token. */
262 if ( pCfgTokenUse
263 && ( pCfgTokenUse->enmType == CFGTOKENTYPE_ID
264 || enmType == CFGTOKENTYPE_ID))
265 {
266 autostartConfigTokenFree(pCfgTokenizer, pCfgTokenUse);
267 pCfgTokenUse = NULL;
268 }
269
270 if (!pCfgTokenUse)
271 {
272 size_t cbToken = sizeof(CFGTOKEN);
273 if (enmType == CFGTOKENTYPE_ID)
274 cbToken += (cchToken + 1) * sizeof(char);
275
276 pCfgTokenUse = (PCFGTOKEN)RTMemAllocZ(cbToken);
277 if (!pCfgTokenUse)
278 rc = VERR_NO_MEMORY;
279 }
280
281 if (RT_SUCCESS(rc))
282 {
283 /* Copy token data. */
284 pCfgTokenUse->enmType = enmType;
285 pCfgTokenUse->cchStart = pCfgTokenizer->cchCurr;
286 pCfgTokenUse->iLine = pCfgTokenizer->iLine;
287 if (enmType == CFGTOKENTYPE_ID)
288 {
289 pCfgTokenUse->u.Id.cchToken = cchToken;
290 memcpy(pCfgTokenUse->u.Id.achToken, pszToken, cchToken);
291 }
292 }
293 else if (pCfgTokenUse)
294 autostartConfigTokenFree(pCfgTokenizer, pCfgTokenUse);
295
296 if (RT_SUCCESS(rc))
297 {
298 /* Set new position in config stream. */
299 pCfgTokenizer->pszLineCurr += cchToken + cchAdvance;
300 pCfgTokenizer->cchCurr += cchToken + cchAdvance;
301 *ppCfgToken = pCfgTokenUse;
302 }
303 }
304
305 return rc;
306}
307
308/**
309 * Destroys the given config tokenizer.
310 *
311 * @returns nothing.
312 * @param pCfgTokenizer The config tokenizer to destroy.
313 */
314static void autostartConfigTokenizerDestroy(PCFGTOKENIZER pCfgTokenizer)
315{
316 if (pCfgTokenizer->pszLine)
317 RTMemFree(pCfgTokenizer->pszLine);
318 if (pCfgTokenizer->hStrmConfig)
319 RTStrmClose(pCfgTokenizer->hStrmConfig);
320 if (pCfgTokenizer->pTokenNext)
321 RTMemFree(pCfgTokenizer->pTokenNext);
322 RTMemFree(pCfgTokenizer);
323}
324
325/**
326 * Creates the config tokenizer from the given filename.
327 *
328 * @returns VBox status code.
329 * @param pszFilename Config filename.
330 * @param ppCfgTokenizer Where to store the pointer to the config tokenizer on
331 * success.
332 */
333static int autostartConfigTokenizerCreate(const char *pszFilename, PCFGTOKENIZER *ppCfgTokenizer)
334{
335 int rc = VINF_SUCCESS;
336 PCFGTOKENIZER pCfgTokenizer = (PCFGTOKENIZER)RTMemAllocZ(sizeof(CFGTOKENIZER));
337
338 if (pCfgTokenizer)
339 {
340 pCfgTokenizer->iLine = 0;
341 pCfgTokenizer->cbLine = 128;
342 pCfgTokenizer->pszLine = (char *)RTMemAllocZ(pCfgTokenizer->cbLine);
343 if (pCfgTokenizer->pszLine)
344 {
345 rc = RTStrmOpen(pszFilename, "r", &pCfgTokenizer->hStrmConfig);
346 if (RT_SUCCESS(rc))
347 {
348 rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer);
349 if (RT_SUCCESS(rc))
350 rc = autostartConfigTokenizerCreateToken(pCfgTokenizer, NULL,
351 &pCfgTokenizer->pTokenNext);
352 }
353 }
354 else
355 rc = VERR_NO_MEMORY;
356 }
357 else
358 rc = VERR_NO_MEMORY;
359
360 if (RT_SUCCESS(rc))
361 *ppCfgTokenizer = pCfgTokenizer;
362 else if ( RT_FAILURE(rc)
363 && pCfgTokenizer)
364 autostartConfigTokenizerDestroy(pCfgTokenizer);
365
366 return rc;
367}
368
369/**
370 * Return the next token from the config stream.
371 *
372 * @returns VBox status code.
373 * @param pCfgTokenizer The config tokenizer.
374 * @param ppCfgToken Where to store the next token.
375 */
376static int autostartConfigTokenizerGetNextToken(PCFGTOKENIZER pCfgTokenizer,
377 PCFGTOKEN *ppCfgToken)
378{
379 *ppCfgToken = pCfgTokenizer->pTokenNext;
380 return autostartConfigTokenizerCreateToken(pCfgTokenizer, NULL, &pCfgTokenizer->pTokenNext);
381}
382
383/**
384 * Returns a stringified version of the token type.
385 *
386 * @returns Stringified version of the token type.
387 * @param enmType Token type.
388 */
389static const char *autostartConfigTokenTypeToStr(CFGTOKENTYPE enmType)
390{
391 switch (enmType)
392 {
393 case CFGTOKENTYPE_COMMA:
394 return ",";
395 case CFGTOKENTYPE_EQUAL:
396 return "=";
397 case CFGTOKENTYPE_CURLY_OPEN:
398 return "{";
399 case CFGTOKENTYPE_CURLY_CLOSING:
400 return "}";
401 case CFGTOKENTYPE_EOF:
402 return "<EOF>";
403 case CFGTOKENTYPE_ID:
404 return "<Identifier>";
405 default:
406 AssertFailed();
407 return "<Invalid>";
408 }
409
410 AssertFailed();
411 return NULL;
412}
413
414/**
415 * Returns a stringified version of the token.
416 *
417 * @returns Stringified version of the token type.
418 * @param pToken Token.
419 */
420static const char *autostartConfigTokenToString(PCFGTOKEN pToken)
421{
422 if (pToken->enmType == CFGTOKENTYPE_ID)
423 return pToken->u.Id.achToken;
424 else
425 return autostartConfigTokenTypeToStr(pToken->enmType);
426}
427
428/**
429 * Returns the length of the token in characters (without zero terminator).
430 *
431 * @returns Token length.
432 * @param pToken Token.
433 */
434static size_t autostartConfigTokenGetLength(PCFGTOKEN pToken)
435{
436 switch (pToken->enmType)
437 {
438 case CFGTOKENTYPE_COMMA:
439 case CFGTOKENTYPE_EQUAL:
440 case CFGTOKENTYPE_CURLY_OPEN:
441 case CFGTOKENTYPE_CURLY_CLOSING:
442 return 1;
443 case CFGTOKENTYPE_EOF:
444 return 0;
445 case CFGTOKENTYPE_ID:
446 return strlen(pToken->u.Id.achToken);
447 default:
448 AssertFailed();
449 return 0;
450 }
451
452 AssertFailed();
453 return 0;
454}
455
456/**
457 * Log unexpected token error.
458 *
459 * @returns nothing.
460 * @param pToken The token which caused the error.
461 * @param pszExpected String of the token which was expected.
462 */
463static void autostartConfigTokenizerMsgUnexpectedToken(PCFGTOKEN pToken, const char *pszExpected)
464{
465 autostartSvcLogError("Unexpected token '%s' at %d:%d.%d, expected '%s'",
466 autostartConfigTokenToString(pToken),
467 pToken->iLine, pToken->cchStart,
468 pToken->cchStart + autostartConfigTokenGetLength(pToken) - 1, pszExpected);
469}
470
471/**
472 * Verfies a token and consumes it.
473 *
474 * @returns VBox status code.
475 * @param pCfgTokenizer The config tokenizer.
476 * @param pszTokenCheck The token to check for.
477 */
478static int autostartConfigTokenizerCheckAndConsume(PCFGTOKENIZER pCfgTokenizer, CFGTOKENTYPE enmType)
479{
480 int rc = VINF_SUCCESS;
481 PCFGTOKEN pCfgToken = NULL;
482
483 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pCfgToken);
484 if (RT_SUCCESS(rc))
485 {
486 if (pCfgToken->enmType != enmType)
487 {
488 autostartConfigTokenizerMsgUnexpectedToken(pCfgToken, autostartConfigTokenTypeToStr(enmType));
489 rc = VERR_INVALID_PARAMETER;
490 }
491
492 autostartConfigTokenFree(pCfgTokenizer, pCfgToken);
493 }
494 return rc;
495}
496
497/**
498 * Consumes the next token in the stream.
499 *
500 * @returns VBox status code.
501 * @param pCfgTokenizer Tokenizer instance data.
502 */
503static int autostartConfigTokenizerConsume(PCFGTOKENIZER pCfgTokenizer)
504{
505 int rc = VINF_SUCCESS;
506 PCFGTOKEN pCfgToken = NULL;
507
508 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pCfgToken);
509 if (RT_SUCCESS(rc))
510 autostartConfigTokenFree(pCfgTokenizer, pCfgToken);
511
512 return rc;
513}
514
515/**
516 * Returns the start of the next token without consuming it.
517 *
518 * @returns The next token without consuming it.
519 * @param pCfgTokenizer Tokenizer instance data.
520 */
521DECLINLINE(PCFGTOKEN) autostartConfigTokenizerPeek(PCFGTOKENIZER pCfgTokenizer)
522{
523 return pCfgTokenizer->pTokenNext;
524}
525
526/**
527 * Check whether the next token is equal to the given one.
528 *
529 * @returns true if the next token in the stream is equal to the given one
530 * false otherwise.
531 * @param pszToken The token to check for.
532 */
533DECLINLINE(bool) autostartConfigTokenizerPeekIsEqual(PCFGTOKENIZER pCfgTokenizer, CFGTOKENTYPE enmType)
534{
535 PCFGTOKEN pToken = autostartConfigTokenizerPeek(pCfgTokenizer);
536 return pToken->enmType == enmType;
537}
538
539/**
540 * Parse a key value node and returns the AST.
541 *
542 * @returns VBox status code.
543 * @param pCfgTokenizer The tokenizer for the config stream.
544 * @param pszKey The key for the pair.
545 * @param ppCfgAst Where to store the resulting AST on success.
546 */
547static int autostartConfigParseValue(PCFGTOKENIZER pCfgTokenizer, const char *pszKey,
548 PCFGAST *ppCfgAst)
549{
550 int rc = VINF_SUCCESS;
551 PCFGTOKEN pToken = NULL;
552
553 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pToken);
554 if ( RT_SUCCESS(rc)
555 && pToken->enmType == CFGTOKENTYPE_ID)
556 {
557 PCFGAST pCfgAst = NULL;
558
559 pCfgAst = (PCFGAST)RTMemAllocZ(RT_OFFSETOF(CFGAST, u.KeyValue.aszValue[pToken->u.Id.cchToken + 1]));
560 if (!pCfgAst)
561 return VERR_NO_MEMORY;
562
563 pCfgAst->enmType = CFGASTNODETYPE_KEYVALUE;
564 pCfgAst->pszKey = RTStrDup(pszKey);
565 if (!pCfgAst->pszKey)
566 {
567 RTMemFree(pCfgAst);
568 return VERR_NO_MEMORY;
569 }
570
571 memcpy(pCfgAst->u.KeyValue.aszValue, pToken->u.Id.achToken, pToken->u.Id.cchToken);
572 pCfgAst->u.KeyValue.cchValue = pToken->u.Id.cchToken;
573 *ppCfgAst = pCfgAst;
574 }
575 else
576 {
577 autostartConfigTokenizerMsgUnexpectedToken(pToken, "non reserved token");
578 rc = VERR_INVALID_PARAMETER;
579 }
580
581 return rc;
582}
583
584/**
585 * Parses a compound node constructing the AST and returning it on success.
586 *
587 * @returns VBox status code.
588 * @param pCfgTokenizer The tokenizer for the config stream.
589 * @param pszScopeId The scope ID of the compound node.
590 * @param ppCfgAst Where to store the resulting AST on success.
591 */
592static int autostartConfigParseCompoundNode(PCFGTOKENIZER pCfgTokenizer, const char *pszScopeId,
593 PCFGAST *ppCfgAst)
594{
595 int rc = VINF_SUCCESS;
596 unsigned cAstNodesMax = 10;
597 unsigned idxAstNodeCur = 0;
598 PCFGAST pCfgAst = NULL;
599
600 pCfgAst = (PCFGAST)RTMemAllocZ(RT_OFFSETOF(CFGAST, u.Compound.apAstNodes[cAstNodesMax]));
601 if (!pCfgAst)
602 return VERR_NO_MEMORY;
603
604 pCfgAst->enmType = CFGASTNODETYPE_COMPOUND;
605 pCfgAst->u.Compound.cAstNodes = 0;
606 pCfgAst->pszKey = RTStrDup(pszScopeId);
607 if (!pCfgAst->pszKey)
608 {
609 RTMemFree(pCfgAst);
610 return VERR_NO_MEMORY;
611 }
612
613 do
614 {
615 PCFGTOKEN pToken = NULL;
616 PCFGAST pAstNode = NULL;
617
618 if ( autostartConfigTokenizerPeekIsEqual(pCfgTokenizer, CFGTOKENTYPE_CURLY_CLOSING)
619 || autostartConfigTokenizerPeekIsEqual(pCfgTokenizer, CFGTOKENTYPE_EOF))
620 break;
621
622 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pToken);
623 if ( RT_SUCCESS(rc)
624 && pToken->enmType == CFGTOKENTYPE_ID)
625 {
626 /* Next must be a = token in all cases at this place. */
627 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, CFGTOKENTYPE_EQUAL);
628 if (RT_SUCCESS(rc))
629 {
630 /* Check whether this is a compound node. */
631 if (autostartConfigTokenizerPeekIsEqual(pCfgTokenizer, CFGTOKENTYPE_CURLY_OPEN))
632 {
633 rc = autostartConfigTokenizerConsume(pCfgTokenizer);
634 if (RT_SUCCESS(rc))
635 rc = autostartConfigParseCompoundNode(pCfgTokenizer, pToken->u.Id.achToken,
636 &pAstNode);
637
638 if (RT_SUCCESS(rc))
639 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, CFGTOKENTYPE_CURLY_CLOSING);
640 }
641 else
642 rc = autostartConfigParseValue(pCfgTokenizer, pToken->u.Id.achToken,
643 &pAstNode);
644 }
645 }
646 else if (RT_SUCCESS(rc))
647 {
648 autostartConfigTokenizerMsgUnexpectedToken(pToken, "non reserved token");
649 rc = VERR_INVALID_PARAMETER;
650 }
651
652 /* Add to the current compound node. */
653 if (RT_SUCCESS(rc))
654 {
655 if (pCfgAst->u.Compound.cAstNodes >= cAstNodesMax)
656 {
657 cAstNodesMax += 10;
658
659 PCFGAST pCfgAstNew = (PCFGAST)RTMemRealloc(pCfgAst, RT_OFFSETOF(CFGAST, u.Compound.apAstNodes[cAstNodesMax]));
660 if (!pCfgAstNew)
661 rc = VERR_NO_MEMORY;
662 else
663 pCfgAst = pCfgAstNew;
664 }
665
666 if (RT_SUCCESS(rc))
667 {
668 pCfgAst->u.Compound.apAstNodes[pCfgAst->u.Compound.cAstNodes] = pAstNode;
669 pCfgAst->u.Compound.cAstNodes++;
670 }
671 }
672
673 autostartConfigTokenFree(pCfgTokenizer, pToken);
674
675 } while (RT_SUCCESS(rc));
676
677 if (RT_SUCCESS(rc))
678 *ppCfgAst = pCfgAst;
679 else
680 autostartConfigAstDestroy(pCfgAst);
681
682 return rc;
683}
684
685DECLHIDDEN(int) autostartParseConfig(const char *pszFilename, PCFGAST *ppCfgAst)
686{
687 PCFGTOKENIZER pCfgTokenizer = NULL;
688 int rc = VINF_SUCCESS;
689 PCFGAST pCfgAst = NULL;
690
691 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
692 AssertPtrReturn(ppCfgAst, VERR_INVALID_POINTER);
693
694 rc = autostartConfigTokenizerCreate(pszFilename, &pCfgTokenizer);
695 if (RT_SUCCESS(rc))
696 {
697 rc = autostartConfigParseCompoundNode(pCfgTokenizer, "", &pCfgAst);
698 if (RT_SUCCESS(rc))
699 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, CFGTOKENTYPE_EOF);
700 }
701
702 if (pCfgTokenizer)
703 autostartConfigTokenizerDestroy(pCfgTokenizer);
704
705 if (RT_SUCCESS(rc))
706 *ppCfgAst = pCfgAst;
707
708 return rc;
709}
710
711DECLHIDDEN(void) autostartConfigAstDestroy(PCFGAST pCfgAst)
712{
713 AssertPtrReturnVoid(pCfgAst);
714
715 switch (pCfgAst->enmType)
716 {
717 case CFGASTNODETYPE_KEYVALUE:
718 {
719 RTMemFree(pCfgAst);
720 break;
721 }
722 case CFGASTNODETYPE_COMPOUND:
723 {
724 for (unsigned i = 0; i < pCfgAst->u.Compound.cAstNodes; i++)
725 autostartConfigAstDestroy(pCfgAst->u.Compound.apAstNodes[i]);
726 RTMemFree(pCfgAst);
727 break;
728 }
729 case CFGASTNODETYPE_LIST:
730 default:
731 AssertMsgFailed(("Invalid AST node type %d\n", pCfgAst->enmType));
732 }
733}
734
735DECLHIDDEN(PCFGAST) autostartConfigAstGetByName(PCFGAST pCfgAst, const char *pszName)
736{
737 if (!pCfgAst)
738 return NULL;
739
740 AssertReturn(pCfgAst->enmType == CFGASTNODETYPE_COMPOUND, NULL);
741
742 for (unsigned i = 0; i < pCfgAst->u.Compound.cAstNodes; i++)
743 {
744 PCFGAST pNode = pCfgAst->u.Compound.apAstNodes[i];
745
746 if (!RTStrCmp(pNode->pszKey, pszName))
747 return pNode;
748 }
749
750 return NULL;
751}
752
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette