Skip to content

Commit a82dcba

Browse files
committed
Update variable resolving logic for pkfconfig
1 parent 7ffed0f commit a82dcba

File tree

1 file changed

+36
-16
lines changed

1 file changed

+36
-16
lines changed

Sources/Build/PkgConfig.swift

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import func POSIX.getenv
1313

1414
enum PkgConfigError: ErrorProtocol {
1515
case CouldNotFindConfigFile
16+
case ParsingError
1617
}
1718

1819
struct PkgConfig {
@@ -91,13 +92,13 @@ struct PkgConfigParser {
9192
let equalsIndex = line.characters.index(of: "=")!
9293
let name = line[line.startIndex..<equalsIndex]
9394
let value = line[equalsIndex.successor()..<line.endIndex]
94-
variables[name] = resolveVariables(value)
95+
variables[name] = try resolveVariables(value)
9596
} else if line.hasPrefix("Requires: ") {
9697
dependencies = parseDependencies(value(line: line))
9798
} else if line.hasPrefix("Libs: ") {
98-
libs = resolveVariables(value(line: line)).chomp()
99+
libs = try resolveVariables(value(line: line)).chomp()
99100
} else if line.hasPrefix("Cflags: ") {
100-
cFlags = resolveVariables( value(line: line)).chomp()
101+
cFlags = try resolveVariables( value(line: line)).chomp()
101102
}
102103
}
103104
}
@@ -121,21 +122,40 @@ struct PkgConfigParser {
121122
return deps
122123
}
123124

124-
private func resolveVariables(_ line: String) -> String {
125-
func resolve(_ string: String) -> String {
126-
var resolvedString = string
127-
guard let dollar = resolvedString.characters.index(of: "$") else { return string }
128-
guard let variableEndIndex = resolvedString.characters.index(of: "}") else {return string }
129-
let variable = string[dollar.successor().successor()..<variableEndIndex]
130-
let value = variables[variable]!
131-
resolvedString = resolvedString[resolvedString.startIndex..<dollar] + value + resolvedString[variableEndIndex.successor()..<resolvedString.endIndex]
132-
return resolvedString
125+
/// Variables occur in form of ${variableName}, we search for a variable linearly
126+
/// in the string and if found, lookup the value of the variable in our dictionary and
127+
/// replace the variable name with its value.
128+
private func resolveVariables(_ line: String) throws -> String {
129+
typealias StringIndex = String.CharacterView.Index
130+
131+
// Returns variable name, start index and end index of a variable in a string if present.
132+
// We make sure it of form ${name} otherwise it is not a variable.
133+
func findVariable(_ fragment: String) -> (name: String, startIndex: StringIndex, endIndex: StringIndex)? {
134+
guard let dollar = fragment.characters.index(of: "$") else { return nil }
135+
guard dollar != fragment.endIndex && fragment.characters[dollar.successor()] == "{" else { return nil }
136+
guard let variableEndIndex = fragment.characters.index(of: "}") else { return nil }
137+
return (fragment[dollar.successor().successor()..<variableEndIndex], dollar, variableEndIndex)
133138
}
134-
var resolved = line
135-
while resolved.characters.contains("$") {
136-
resolved = resolve(resolved)
139+
140+
var result = ""
141+
var fragment = line
142+
while !fragment.isEmpty {
143+
// Look for a variable in our current fragment.
144+
if let variable = findVariable(fragment) {
145+
// Append the contents before the variable.
146+
result += fragment[fragment.characters.startIndex..<variable.startIndex]
147+
guard let variableValue = variables[variable.name] else { throw PkgConfigError.ParsingError }
148+
// Append the value of the variable.
149+
result += variableValue
150+
// Update the fragment with post variable string.
151+
fragment = fragment[variable.endIndex.successor()..<fragment.characters.endIndex]
152+
} else {
153+
// No variable found, just append rest of the fragment to result.
154+
result += fragment
155+
fragment = ""
156+
}
137157
}
138-
return resolved
158+
return result
139159
}
140160

141161
private func value(line: String) -> String {

0 commit comments

Comments
 (0)