| 154 | } |
| 155 | |
| 156 | QString extractExeName(const QString &execLine) |
| 157 | { |
| 158 | QString remaining = execLine; |
| 159 | QString block; |
| 160 | QString path; |
| 161 | bool isFlatpak = false; |
| 162 | bool isSnap = false; |
| 163 | |
| 164 | // Special handling for snaps |
| 165 | int idx = execLine.indexOf("/snap/bin/"); |
| 166 | if (idx != -1) { |
| 167 | isSnap = true; |
| 168 | } |
| 169 | |
| 170 | while (!remaining.isEmpty()) { |
| 171 | int end; |
| 172 | // if quoted, this block ends at the end quote, otherwise at the first space |
| 173 | if (remaining[0] == '"') { |
| 174 | end = remaining.indexOf('"', 1); |
| 175 | block = unescape(remaining.mid(1, end - 1)); |
| 176 | remaining = remaining.mid(end + 1); |
| 177 | } else { |
| 178 | end = remaining.indexOf(' '); |
| 179 | if (end == -1) { |
| 180 | block = remaining; |
| 181 | remaining = ""; |
| 182 | } else { |
| 183 | block = remaining.first(end); |
| 184 | remaining = remaining.mid(end + 1); |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | if (isSnap && block.startsWith("/snap/bin/")) { |
| 189 | return block; |
| 190 | } |
| 191 | |
| 192 | // ignore env-var assignments and 'env'; this also filters --branch=, --command=, etc. |
| 193 | if (block.contains("=") || block == "env") { |
| 194 | continue; |
| 195 | } |
| 196 | |
| 197 | // skip Exec field codes (%U, %F, ...) and Flatpak file-forwarding markers (@@, @@u, ...) |
| 198 | if (block.startsWith("%") || block.startsWith("@@")) { |
| 199 | continue; |
| 200 | } |
| 201 | |
| 202 | if (isFlatpak) { |
| 203 | // After 'flatpak run', the first reverse-DNS-shaped positional is the app ID |
| 204 | // (e.g. org.mozilla.firefox). 'run' itself has no dot, so it's skipped here. |
| 205 | if (block.contains(".")) { |
| 206 | return block; |
| 207 | } |
| 208 | continue; |
| 209 | } |
| 210 | |
| 211 | path = convertToAbsolutePath(block); |
| 212 | if (!path.isEmpty()) { |
| 213 | if (QFileInfo(QFile(path)).fileName() == "flatpak") { |
no test coverage detected