| ... | ... | @@ -0,0 +1,444 @@ |
| 1 | const std = @import("std"); |
| 2 | |
| 3 | pub fn version_from_build(build: []const u8) !std.builtin.Version { |
| 4 | // build format: |
| 5 | // 19E287 (example) |
| 6 | // xxyzzz |
| 7 | // |
| 8 | // major = 10 |
| 9 | // minor = x - 4 = 19 - 4 = 15 |
| 10 | // patch = ascii(y) - 'A' = 'E' - 'A' = 69 - 65 = 4 |
| 11 | // answer: 10.15.4 |
| 12 | // |
| 13 | // note: patch is typical but with some older releases (before 10.8) zzz is considered |
| 14 | |
| 15 | // never return anything below 10.0.0 |
| 16 | var result = std.builtin.Version{ .major = 10, .minor = 0, .patch = 0 }; |
| 17 | |
| 18 | // parse format-x |
| 19 | var yindex: usize = 0; |
| 20 | { |
| 21 | while (yindex < build.len) : (yindex += 1) { |
| 22 | if (build[yindex] < '0' or build[yindex] > '9') break; |
| 23 | } |
| 24 | if (yindex == 0) return result; |
| 25 | const x = std.fmt.parseUnsigned(u16, build[0..yindex], 10) catch return error.InvalidVersion; |
| 26 | if (x < 4) return result; |
| 27 | result.minor = x - 4; |
| 28 | } |
| 29 | |
| 30 | // parse format-y, format-z |
| 31 | { |
| 32 | // expect two more |
| 33 | if (build.len < yindex + 2) return error.InvalidVersion; |
| 34 | const y = build[yindex]; |
| 35 | if (y < 'A') return error.InvalidVersion; |
| 36 | var zend = yindex + 1; |
| 37 | while (zend < build.len) { |
| 38 | if (build[zend] < '0' or build[zend] > '9') break; |
| 39 | zend += 1; |
| 40 | } |
| 41 | if (zend == yindex + 1) return error.InvalidVersion; |
| 42 | const z = std.fmt.parseUnsigned(u16, build[yindex + 1..zend], 10) catch return error.InvalidVersion; |
| 43 | |
| 44 | result.patch = switch (result.minor) { |
| 45 | // TODO: compiler complains without explicit @as() coercion |
| 46 | 0 => @as(u32, switch (y) { // Cheetah: 10.0 |
| 47 | 'K' => 0, |
| 48 | 'L' => 1, |
| 49 | 'P' => @as(u32, block: { |
| 50 | if (z < 13) break :block 2; |
| 51 | break :block 3; |
| 52 | }), |
| 53 | 'Q' => 4, |
| 54 | else => return error.InvalidVersion, |
| 55 | }), |
| 56 | 1 => @as(u32, switch (y) { // Puma: 10.1 |
| 57 | 'G' => 0, |
| 58 | 'M' => 1, |
| 59 | 'P' => 2, |
| 60 | 'Q' => @as(u32, block: { |
| 61 | if (z < 125) break :block 3; |
| 62 | break :block 4; |
| 63 | }), |
| 64 | 'S' => 5, |
| 65 | else => return error.InvalidVersion, |
| 66 | }), |
| 67 | 2 => @as(u32, switch (y) { // Jaguar: 10.2 |
| 68 | 'C' => 0, |
| 69 | 'D' => 1, |
| 70 | 'F' => 2, |
| 71 | 'G' => 3, |
| 72 | 'I' => 4, |
| 73 | 'L' => @as(u32, block: { |
| 74 | if (z < 60) break :block 5; |
| 75 | break :block 6; |
| 76 | }), |
| 77 | 'R' => @as(u32, block: { |
| 78 | if (z < 73) break :block 7; |
| 79 | break :block 8; |
| 80 | }), |
| 81 | 'S' => 8, |
| 82 | else => return error.InvalidVersion, |
| 83 | }), |
| 84 | 3 => @as(u32, switch (y) { // Panther: 10.3 |
| 85 | 'B' => 0, |
| 86 | 'C' => 1, |
| 87 | 'D' => 2, |
| 88 | 'F' => 3, |
| 89 | 'H' => 4, |
| 90 | 'M' => 5, |
| 91 | 'R' => 6, |
| 92 | 'S' => 7, |
| 93 | 'U' => 8, |
| 94 | 'W' => 9, |
| 95 | else => return error.InvalidVersion, |
| 96 | }), |
| 97 | 4 => @as(u32, switch (y) { // Tiger: 10.4 |
| 98 | 'A' => 0, |
| 99 | 'B' => 1, |
| 100 | 'C', 'E', => 2, |
| 101 | 'F' => 3, |
| 102 | 'G' => @as(u32, block: { |
| 103 | if (z >= 1454) break :block 5; |
| 104 | break :block 4; |
| 105 | }), |
| 106 | 'H' => 5, |
| 107 | 'I' => 6, |
| 108 | 'J', 'K', 'N', => 7, |
| 109 | 'L' => 8, |
| 110 | 'P' => 9, |
| 111 | 'R' => 10, |
| 112 | 'S' => 11, |
| 113 | else => return error.InvalidVersion, |
| 114 | }), |
| 115 | 5 => @as(u32, switch (y) { // Leopard: 10.5 |
| 116 | 'A' => 0, |
| 117 | 'B' => 1, |
| 118 | 'C' => 2, |
| 119 | 'D' => 3, |
| 120 | 'E' => 4, |
| 121 | 'F' => 5, |
| 122 | 'G' => 6, |
| 123 | 'J' => 7, |
| 124 | 'L' => 8, |
| 125 | else => return error.InvalidVersion, |
| 126 | }), |
| 127 | 6 => @as(u32, switch (y) { // Snow Leopard: 10.6 |
| 128 | 'A' => 0, |
| 129 | 'B' => 1, |
| 130 | 'C' => 2, |
| 131 | 'D' => 3, |
| 132 | 'F' => 4, |
| 133 | 'H' => 5, |
| 134 | 'J' => @as(u32, block: { |
| 135 | if (z < 869) break :block 6; |
| 136 | break :block 7; |
| 137 | }), |
| 138 | 'K' => 8, |
| 139 | else => return error.InvalidVersion, |
| 140 | }), |
| 141 | 7 => @as(u32, switch (y) { // Snow Leopard: 10.6 |
| 142 | 'A' => 0, |
| 143 | 'B' => 1, |
| 144 | 'C' => 2, |
| 145 | 'D' => 3, |
| 146 | 'E' => 4, |
| 147 | 'G' => 5, |
| 148 | else => return error.InvalidVersion, |
| 149 | }), |
| 150 | else => y - 'A', |
| 151 | }; |
| 152 | } |
| 153 | return result; |
| 154 | } |
| 155 | |
| 156 | test "version_from_build" { |
| 157 | // see https://en.wikipedia.org/wiki/MacOS_version_history#Releases |
| 158 | const known = [_][2][]const u8{ |
| 159 | .{ "4K78", "10.0.0" }, |
| 160 | .{ "4L13", "10.0.1" }, |
| 161 | .{ "4P12", "10.0.2" }, |
| 162 | .{ "4P13", "10.0.3" }, |
| 163 | .{ "4Q12", "10.0.4" }, |
| 164 | |
| 165 | .{ "5G64", "10.1.0" }, |
| 166 | .{ "5M28", "10.1.1" }, |
| 167 | .{ "5P48", "10.1.2" }, |
| 168 | .{ "5Q45", "10.1.3" }, |
| 169 | .{ "5Q125", "10.1.4" }, |
| 170 | .{ "5S60", "10.1.5" }, |
| 171 | |
| 172 | .{ "6C115", "10.2.0" }, |
| 173 | .{ "6C115a", "10.2.0" }, |
| 174 | .{ "6D52", "10.2.1" }, |
| 175 | .{ "6F21", "10.2.2" }, |
| 176 | .{ "6G30", "10.2.3" }, |
| 177 | .{ "6G37", "10.2.3" }, |
| 178 | .{ "6G50", "10.2.3" }, |
| 179 | .{ "6I32", "10.2.4" }, |
| 180 | .{ "6L29", "10.2.5" }, |
| 181 | .{ "6L60", "10.2.6" }, |
| 182 | .{ "6R65", "10.2.7" }, |
| 183 | .{ "6R73", "10.2.8" }, |
| 184 | .{ "6S90", "10.2.8" }, |
| 185 | |
| 186 | .{ "7B85", "10.3.0" }, |
| 187 | .{ "7B86", "10.3.0" }, |
| 188 | .{ "7C107", "10.3.1" }, |
| 189 | .{ "7D24", "10.3.2" }, |
| 190 | .{ "7D28", "10.3.2" }, |
| 191 | .{ "7F44", "10.3.3" }, |
| 192 | .{ "7H63", "10.3.4" }, |
| 193 | .{ "7M34", "10.3.5" }, |
| 194 | .{ "7R28", "10.3.6" }, |
| 195 | .{ "7S215", "10.3.7" }, |
| 196 | .{ "7U16", "10.3.8" }, |
| 197 | .{ "7W98", "10.3.9" }, |
| 198 | |
| 199 | .{ "8A428", "10.4.0" }, |
| 200 | .{ "8A432", "10.4.0" }, |
| 201 | .{ "8B15", "10.4.1" }, |
| 202 | .{ "8B17", "10.4.1" }, |
| 203 | .{ "8C46", "10.4.2" }, |
| 204 | .{ "8C47", "10.4.2" }, |
| 205 | .{ "8E102", "10.4.2" }, |
| 206 | .{ "8E45", "10.4.2" }, |
| 207 | .{ "8E90", "10.4.2" }, |
| 208 | .{ "8F46", "10.4.3" }, |
| 209 | .{ "8G32", "10.4.4" }, |
| 210 | .{ "8G1165", "10.4.4" }, |
| 211 | .{ "8H14", "10.4.5" }, |
| 212 | .{ "8G1454", "10.4.5" }, |
| 213 | .{ "8I127", "10.4.6" }, |
| 214 | .{ "8I1119", "10.4.6" }, |
| 215 | .{ "8J135", "10.4.7" }, |
| 216 | .{ "8J2135a", "10.4.7" }, |
| 217 | .{ "8K1079", "10.4.7" }, |
| 218 | .{ "8N5107", "10.4.7" }, |
| 219 | .{ "8L127", "10.4.8" }, |
| 220 | .{ "8L2127", "10.4.8" }, |
| 221 | .{ "8P135", "10.4.9" }, |
| 222 | .{ "8P2137", "10.4.9" }, |
| 223 | .{ "8R218", "10.4.10" }, |
| 224 | .{ "8R2218", "10.4.10" }, |
| 225 | .{ "8R2232", "10.4.10" }, |
| 226 | .{ "8S165", "10.4.11" }, |
| 227 | .{ "8S2167", "10.4.11" }, |
| 228 | |
| 229 | .{ "9A581", "10.5.0" }, |
| 230 | .{ "9B18", "10.5.1" }, |
| 231 | .{ "9C31", "10.5.2" }, |
| 232 | .{ "9C7010", "10.5.2" }, |
| 233 | .{ "9D34", "10.5.3" }, |
| 234 | .{ "9E17", "10.5.4" }, |
| 235 | .{ "9F33", "10.5.5" }, |
| 236 | .{ "9G55", "10.5.6" }, |
| 237 | .{ "9G66", "10.5.6" }, |
| 238 | .{ "9J61", "10.5.7" }, |
| 239 | .{ "9L30", "10.5.8" }, |
| 240 | |
| 241 | .{ "10A432", "10.6.0" }, |
| 242 | .{ "10A433", "10.6.0" }, |
| 243 | .{ "10B504", "10.6.1" }, |
| 244 | .{ "10C540", "10.6.2" }, |
| 245 | .{ "10D573", "10.6.3" }, |
| 246 | .{ "10D575", "10.6.3" }, |
| 247 | .{ "10D578", "10.6.3" }, |
| 248 | .{ "10F569", "10.6.4" }, |
| 249 | .{ "10H574", "10.6.5" }, |
| 250 | .{ "10J567", "10.6.6" }, |
| 251 | .{ "10J869", "10.6.7" }, |
| 252 | .{ "10J3250", "10.6.7" }, |
| 253 | .{ "10J4138", "10.6.7" }, |
| 254 | .{ "10K540", "10.6.8" }, |
| 255 | .{ "10K549", "10.6.8" }, |
| 256 | |
| 257 | .{ "11A511", "10.7.0" }, |
| 258 | .{ "11A511s", "10.7.0" }, |
| 259 | .{ "11A2061", "10.7.0" }, |
| 260 | .{ "11A2063", "10.7.0" }, |
| 261 | .{ "11B26", "10.7.1" }, |
| 262 | .{ "11B2118", "10.7.1" }, |
| 263 | .{ "11C74", "10.7.2" }, |
| 264 | .{ "11D50", "10.7.3" }, |
| 265 | .{ "11E53", "10.7.4" }, |
| 266 | .{ "11G56", "10.7.5" }, |
| 267 | .{ "11G63", "10.7.5" }, |
| 268 | |
| 269 | .{ "12A269", "10.8.0" }, |
| 270 | .{ "12B19", "10.8.1" }, |
| 271 | .{ "12C54", "10.8.2" }, |
| 272 | .{ "12C60", "10.8.2" }, |
| 273 | .{ "12C2034", "10.8.2" }, |
| 274 | .{ "12C3104", "10.8.2" }, |
| 275 | .{ "12D78", "10.8.3" }, |
| 276 | .{ "12E55", "10.8.4" }, |
| 277 | .{ "12E3067", "10.8.4" }, |
| 278 | .{ "12E4022", "10.8.4" }, |
| 279 | .{ "12F37", "10.8.5" }, |
| 280 | .{ "12F45", "10.8.5" }, |
| 281 | .{ "12F2501", "10.8.5" }, |
| 282 | .{ "12F2518", "10.8.5" }, |
| 283 | .{ "12F2542", "10.8.5" }, |
| 284 | .{ "12F2560", "10.8.5" }, |
| 285 | |
| 286 | .{ "13A603", "10.9.0" }, |
| 287 | .{ "13B42", "10.9.1" }, |
| 288 | .{ "13C64", "10.9.2" }, |
| 289 | .{ "13C1021", "10.9.2" }, |
| 290 | .{ "13D65", "10.9.3" }, |
| 291 | .{ "13E28", "10.9.4" }, |
| 292 | .{ "13F34", "10.9.5" }, |
| 293 | .{ "13F1066", "10.9.5" }, |
| 294 | .{ "13F1077", "10.9.5" }, |
| 295 | .{ "13F1096", "10.9.5" }, |
| 296 | .{ "13F1112", "10.9.5" }, |
| 297 | .{ "13F1134", "10.9.5" }, |
| 298 | .{ "13F1507", "10.9.5" }, |
| 299 | .{ "13F1603", "10.9.5" }, |
| 300 | .{ "13F1712", "10.9.5" }, |
| 301 | .{ "13F1808", "10.9.5" }, |
| 302 | .{ "13F1911", "10.9.5" }, |
| 303 | |
| 304 | .{ "14A389", "10.10.0" }, |
| 305 | .{ "14B25", "10.10.1" }, |
| 306 | .{ "14C109", "10.10.2" }, |
| 307 | .{ "14C1510", "10.10.2" }, |
| 308 | .{ "14C1514", "10.10.2" }, |
| 309 | .{ "14C2043", "10.10.2" }, |
| 310 | .{ "14C2513", "10.10.2" }, |
| 311 | .{ "14D131", "10.10.3" }, |
| 312 | .{ "14D136", "10.10.3" }, |
| 313 | .{ "14E46", "10.10.4" }, |
| 314 | .{ "14F27", "10.10.5" }, |
| 315 | .{ "14F1021", "10.10.5" }, |
| 316 | .{ "14F1505", "10.10.5" }, |
| 317 | .{ "14F1509", "10.10.5" }, |
| 318 | .{ "14F1605", "10.10.5" }, |
| 319 | .{ "14F1713", "10.10.5" }, |
| 320 | .{ "14F1808", "10.10.5" }, |
| 321 | .{ "14F1909", "10.10.5" }, |
| 322 | .{ "14F1912", "10.10.5" }, |
| 323 | .{ "14F2009", "10.10.5" }, |
| 324 | .{ "14F2109", "10.10.5" }, |
| 325 | .{ "14F2315", "10.10.5" }, |
| 326 | .{ "14F2411", "10.10.5" }, |
| 327 | .{ "14F2511", "10.10.5" }, |
| 328 | |
| 329 | .{ "15A284", "10.11.0" }, |
| 330 | .{ "15B42", "10.11.1" }, |
| 331 | .{ "15C50", "10.11.2" }, |
| 332 | .{ "15D21", "10.11.3" }, |
| 333 | .{ "15E65", "10.11.4" }, |
| 334 | .{ "15F34", "10.11.5" }, |
| 335 | .{ "15G31", "10.11.6" }, |
| 336 | .{ "15G1004", "10.11.6" }, |
| 337 | .{ "15G1011", "10.11.6" }, |
| 338 | .{ "15G1108", "10.11.6" }, |
| 339 | .{ "15G1212", "10.11.6" }, |
| 340 | .{ "15G1217", "10.11.6" }, |
| 341 | .{ "15G1421", "10.11.6" }, |
| 342 | .{ "15G1510", "10.11.6" }, |
| 343 | .{ "15G1611", "10.11.6" }, |
| 344 | .{ "15G17023", "10.11.6" }, |
| 345 | .{ "15G18013", "10.11.6" }, |
| 346 | .{ "15G19009", "10.11.6" }, |
| 347 | .{ "15G20015", "10.11.6" }, |
| 348 | .{ "15G21013", "10.11.6" }, |
| 349 | .{ "15G22010", "10.11.6" }, |
| 350 | |
| 351 | .{ "16A323", "10.12.0" }, |
| 352 | .{ "16B2555", "10.12.1" }, |
| 353 | .{ "16B2657", "10.12.1" }, |
| 354 | .{ "16C67", "10.12.2" }, |
| 355 | .{ "16C68", "10.12.2" }, |
| 356 | .{ "16D32", "10.12.3" }, |
| 357 | .{ "16E195", "10.12.4" }, |
| 358 | .{ "16F73", "10.12.5" }, |
| 359 | .{ "16F2073", "10.12.5" }, |
| 360 | .{ "16G29", "10.12.6" }, |
| 361 | .{ "16G1036", "10.12.6" }, |
| 362 | .{ "16G1114", "10.12.6" }, |
| 363 | .{ "16G1212", "10.12.6" }, |
| 364 | .{ "16G1314", "10.12.6" }, |
| 365 | .{ "16G1408", "10.12.6" }, |
| 366 | .{ "16G1510", "10.12.6" }, |
| 367 | .{ "16G1618", "10.12.6" }, |
| 368 | .{ "16G1710", "10.12.6" }, |
| 369 | .{ "16G1815", "10.12.6" }, |
| 370 | .{ "16G1917", "10.12.6" }, |
| 371 | .{ "16G1918", "10.12.6" }, |
| 372 | .{ "16G2016", "10.12.6" }, |
| 373 | .{ "16G2127", "10.12.6" }, |
| 374 | .{ "16G2128", "10.12.6" }, |
| 375 | .{ "16G2136", "10.12.6" }, |
| 376 | |
| 377 | .{ "17A365", "10.13.0" }, |
| 378 | .{ "17A405", "10.13.0" }, |
| 379 | .{ "17B48", "10.13.1" }, |
| 380 | .{ "17B1002", "10.13.1" }, |
| 381 | .{ "17B1003", "10.13.1" }, |
| 382 | .{ "17C88", "10.13.2" }, |
| 383 | .{ "17C89", "10.13.2" }, |
| 384 | .{ "17C205", "10.13.2" }, |
| 385 | .{ "17C2205", "10.13.2" }, |
| 386 | .{ "17D47", "10.13.3" }, |
| 387 | .{ "17D2047", "10.13.3" }, |
| 388 | .{ "17D102", "10.13.3" }, |
| 389 | .{ "17D2102", "10.13.3" }, |
| 390 | .{ "17E199", "10.13.4" }, |
| 391 | .{ "17E202", "10.13.4" }, |
| 392 | .{ "17F77", "10.13.5" }, |
| 393 | .{ "17G65", "10.13.6" }, |
| 394 | .{ "17G2208", "10.13.6" }, |
| 395 | .{ "17G3025", "10.13.6" }, |
| 396 | .{ "17G4015", "10.13.6" }, |
| 397 | .{ "17G5019", "10.13.6" }, |
| 398 | .{ "17G6029", "10.13.6" }, |
| 399 | .{ "17G6030", "10.13.6" }, |
| 400 | .{ "17G7024", "10.13.6" }, |
| 401 | .{ "17G8029", "10.13.6" }, |
| 402 | .{ "17G8030", "10.13.6" }, |
| 403 | .{ "17G8037", "10.13.6" }, |
| 404 | .{ "17G9016", "10.13.6" }, |
| 405 | .{ "17G10021", "10.13.6" }, |
| 406 | .{ "17G11023", "10.13.6" }, |
| 407 | .{ "17G12034", "10.13.6" }, |
| 408 | |
| 409 | .{ "18A391", "10.14.0" }, |
| 410 | .{ "18B75", "10.14.1" }, |
| 411 | .{ "18B2107", "10.14.1" }, |
| 412 | .{ "18B3094", "10.14.1" }, |
| 413 | .{ "18C54", "10.14.2" }, |
| 414 | .{ "18D42", "10.14.3" }, |
| 415 | .{ "18D43", "10.14.3" }, |
| 416 | .{ "18D109", "10.14.3" }, |
| 417 | .{ "18E226", "10.14.4" }, |
| 418 | .{ "18E227", "10.14.4" }, |
| 419 | .{ "18F132", "10.14.5" }, |
| 420 | .{ "18G84", "10.14.6" }, |
| 421 | .{ "18G87", "10.14.6" }, |
| 422 | .{ "18G95", "10.14.6" }, |
| 423 | .{ "18G103", "10.14.6" }, |
| 424 | .{ "18G1012", "10.14.6" }, |
| 425 | .{ "18G2022", "10.14.6" }, |
| 426 | .{ "18G3020", "10.14.6" }, |
| 427 | .{ "18G4032", "10.14.6" }, |
| 428 | |
| 429 | .{ "19A583", "10.15.0" }, |
| 430 | .{ "19A602", "10.15.0" }, |
| 431 | .{ "19A603", "10.15.0" }, |
| 432 | .{ "19B88", "10.15.1" }, |
| 433 | .{ "19C57", "10.15.2" }, |
| 434 | .{ "19D76", "10.15.3" }, |
| 435 | .{ "19E266", "10.15.4" }, |
| 436 | .{ "19E287", "10.15.4" }, |
| 437 | }; |
| 438 | for (known) |pair| { |
| 439 | var buf: [32]u8 = undefined; |
| 440 | const ver = try version_from_build(pair[0]); |
| 441 | const sver = try std.fmt.bufPrint(buf[0..], "{}.{}.{}", .{ver.major, ver.minor, ver.patch}); |
| 442 | std.testing.expect(std.mem.eql(u8, sver, pair[1])); |
| 443 | } |
| 444 | } |