@@ -13,6 +13,7 @@ import func POSIX.getenv
13
13
14
14
enum PkgConfigError : ErrorProtocol {
15
15
case CouldNotFindConfigFile
16
+ case ParsingError
16
17
}
17
18
18
19
struct PkgConfig {
@@ -91,13 +92,13 @@ struct PkgConfigParser {
91
92
let equalsIndex = line. characters. index ( of: " = " ) !
92
93
let name = line [ line. startIndex..< equalsIndex]
93
94
let value = line [ equalsIndex. successor ( ) ..< line. endIndex]
94
- variables [ name] = resolveVariables ( value)
95
+ variables [ name] = try resolveVariables ( value)
95
96
} else if line. hasPrefix ( " Requires: " ) {
96
97
dependencies = parseDependencies ( value ( line: line) )
97
98
} else if line. hasPrefix ( " Libs: " ) {
98
- libs = resolveVariables ( value ( line: line) ) . chomp ( )
99
+ libs = try resolveVariables ( value ( line: line) ) . chomp ( )
99
100
} else if line. hasPrefix ( " Cflags: " ) {
100
- cFlags = resolveVariables ( value ( line: line) ) . chomp ( )
101
+ cFlags = try resolveVariables ( value ( line: line) ) . chomp ( )
101
102
}
102
103
}
103
104
}
@@ -121,21 +122,41 @@ struct PkgConfigParser {
121
122
return deps
122
123
}
123
124
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)
133
139
}
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
+ }
137
158
}
138
- return resolved
159
+ return result
139
160
}
140
161
141
162
private func value( line: String ) -> String {
0 commit comments