nom_kconfig/entry/
source.rs

1use std::path::PathBuf;
2
3use nom::{
4    branch::alt,
5    bytes::complete::tag,
6    character::complete::{alphanumeric1, one_of},
7    combinator::{cut, map, recognize},
8    error::{Error, ErrorKind, ParseError},
9    multi::many1,
10    sequence::delimited,
11    IResult,
12};
13use regex::Regex;
14
15use crate::{
16    kconfig::{parse_kconfig, Kconfig},
17    util::{ws, wsi},
18    KconfigFile, KconfigInput,
19};
20
21pub fn parse_filepath(input: KconfigInput) -> IResult<KconfigInput, &str> {
22    map(
23        recognize(ws(many1(alt((
24            alphanumeric1::<KconfigInput, _>,
25            recognize(one_of(".$()-_$/")),
26        ))))),
27        |d| d.fragment().to_owned(),
28    )(input)
29}
30
31pub fn parse_source(input: KconfigInput) -> IResult<KconfigInput, Source> {
32    let (input, _) = ws(tag("source"))(input)?;
33    let (input, file) = wsi(alt((
34        delimited(tag("\""), parse_filepath, tag("\"")),
35        parse_filepath,
36    )))(input)?;
37    let source_kconfig_file = KconfigFile::new(input.clone().extra.root_dir, PathBuf::from(file));
38    if is_dynamic_source(file) {
39        return Ok((
40            input,
41            Source {
42                file: file.to_string(),
43                ..Default::default()
44            },
45        ));
46    }
47    let source_content = source_kconfig_file
48        .read_to_string()
49        .map_err(|_| nom::Err::Error(Error::from_error_kind(input.clone(), ErrorKind::Fail)))?;
50
51    let binding = source_content.clone();
52    #[allow(clippy::let_and_return)]
53    let x = match cut(parse_kconfig)(KconfigInput::new_extra(
54        &binding,
55        source_kconfig_file.clone(),
56    )) {
57        Ok((_, kconfig)) => Ok((input, kconfig)),
58        Err(_e) => Err(nom::Err::Error(nom::error::Error::new(
59            KconfigInput::new_extra("", source_kconfig_file),
60            ErrorKind::Fail,
61        ))),
62    };
63    x
64}
65
66fn is_dynamic_source(file: &str) -> bool {
67    let re = Regex::new("\\$(.+)").unwrap();
68    re.is_match(file)
69}
70
71/// Entry that reads the specified configuration file. This file is always parsed.
72pub type Source = Kconfig;