VirtualBox

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

Last change on this file since 74942 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use