Skip to content

Commit ee4e043

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

File tree

1 file changed

+37
-16
lines changed

1 file changed

+37
-16
lines changed

Sources/Build/PkgConfig.swift

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

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

0 commit comments

Comments
 (0)