@@ -1294,34 +1294,34 @@ _compareTag(const wchar_t *x, const wchar_t *y)
1294
1294
1295
1295
1296
1296
int
1297
- addEnvironmentInfo (EnvironmentInfo * * root , EnvironmentInfo * node )
1297
+ addEnvironmentInfo (EnvironmentInfo * * root , EnvironmentInfo * parent , EnvironmentInfo * node )
1298
1298
{
1299
1299
EnvironmentInfo * r = * root ;
1300
1300
if (!r ) {
1301
1301
* root = node ;
1302
- node -> parent = NULL ;
1302
+ node -> parent = parent ;
1303
1303
return 0 ;
1304
1304
}
1305
1305
// Sort by company name
1306
1306
switch (_compareCompany (node -> company , r -> company )) {
1307
1307
case -1 :
1308
- return addEnvironmentInfo (& r -> prev , node );
1308
+ return addEnvironmentInfo (& r -> prev , r , node );
1309
1309
case 1 :
1310
- return addEnvironmentInfo (& r -> next , node );
1310
+ return addEnvironmentInfo (& r -> next , r , node );
1311
1311
case 0 :
1312
1312
break ;
1313
1313
}
1314
1314
// Then by tag (descending)
1315
1315
switch (_compareTag (node -> tag , r -> tag )) {
1316
1316
case -1 :
1317
- return addEnvironmentInfo (& r -> next , node );
1317
+ return addEnvironmentInfo (& r -> next , r , node );
1318
1318
case 1 :
1319
- return addEnvironmentInfo (& r -> prev , node );
1319
+ return addEnvironmentInfo (& r -> prev , r , node );
1320
1320
case 0 :
1321
1321
break ;
1322
1322
}
1323
1323
// Then keep the one with the lowest internal sort key
1324
- if (r -> internalSortKey < node -> internalSortKey ) {
1324
+ if (node -> internalSortKey < r -> internalSortKey ) {
1325
1325
// Replace the current node
1326
1326
node -> parent = r -> parent ;
1327
1327
if (node -> parent ) {
@@ -1334,9 +1334,16 @@ addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node)
1334
1334
freeEnvironmentInfo (node );
1335
1335
return RC_INTERNAL_ERROR ;
1336
1336
}
1337
+ } else {
1338
+ // If node has no parent, then it is the root.
1339
+ * root = node ;
1337
1340
}
1341
+
1338
1342
node -> next = r -> next ;
1339
1343
node -> prev = r -> prev ;
1344
+
1345
+ debug (L"# replaced %s/%s/%i in tree\n" , node -> company , node -> tag , node -> internalSortKey );
1346
+ freeEnvironmentInfo (r );
1340
1347
} else {
1341
1348
debug (L"# not adding %s/%s/%i to tree\n" , node -> company , node -> tag , node -> internalSortKey );
1342
1349
return RC_DUPLICATE_ITEM ;
@@ -1392,6 +1399,100 @@ _combineWithInstallDir(const wchar_t **dest, const wchar_t *installDir, const wc
1392
1399
}
1393
1400
1394
1401
1402
+ bool
1403
+ _isLegacyVersion (EnvironmentInfo * env )
1404
+ {
1405
+ // Check if backwards-compatibility is required.
1406
+ // Specifically PythonCore versions 2.X and 3.0 - 3.5 do not implement PEP 514.
1407
+ if (0 != _compare (env -> company , -1 , L"PythonCore" , -1 )) {
1408
+ return false;
1409
+ }
1410
+
1411
+ int versionMajor , versionMinor ;
1412
+ int n = swscanf_s (env -> tag , L"%d.%d" , & versionMajor , & versionMinor );
1413
+ if (n != 2 ) {
1414
+ debug (L"# %s/%s has an invalid version tag\n" , env -> company , env -> tag );
1415
+ return false;
1416
+ }
1417
+
1418
+ return versionMajor == 2
1419
+ || (versionMajor == 3 && versionMinor >= 0 && versionMinor <= 5 );
1420
+ }
1421
+
1422
+ int
1423
+ _registryReadLegacyEnvironment (const SearchInfo * search , HKEY root , EnvironmentInfo * env , const wchar_t * fallbackArch )
1424
+ {
1425
+ // Backwards-compatibility for PythonCore versions which do not implement PEP 514.
1426
+ int exitCode = _combineWithInstallDir (
1427
+ & env -> executablePath ,
1428
+ env -> installDir ,
1429
+ search -> executable ,
1430
+ search -> executableLength
1431
+ );
1432
+ if (exitCode ) {
1433
+ return exitCode ;
1434
+ }
1435
+
1436
+ if (search -> windowed ) {
1437
+ exitCode = _registryReadString (& env -> executableArgs , root , L"InstallPath" , L"WindowedExecutableArguments" );
1438
+ }
1439
+ else {
1440
+ exitCode = _registryReadString (& env -> executableArgs , root , L"InstallPath" , L"ExecutableArguments" );
1441
+ }
1442
+ if (exitCode ) {
1443
+ return exitCode ;
1444
+ }
1445
+
1446
+ if (fallbackArch ) {
1447
+ copyWstr (& env -> architecture , fallbackArch );
1448
+ } else {
1449
+ DWORD binaryType ;
1450
+ BOOL success = GetBinaryTypeW (env -> executablePath , & binaryType );
1451
+ if (!success ) {
1452
+ return RC_NO_PYTHON ;
1453
+ }
1454
+
1455
+ switch (binaryType ) {
1456
+ case SCS_32BIT_BINARY :
1457
+ copyWstr (& env -> architecture , L"32bit" );
1458
+ break ;
1459
+ case SCS_64BIT_BINARY :
1460
+ copyWstr (& env -> architecture , L"64bit" );
1461
+ break ;
1462
+ default :
1463
+ return RC_NO_PYTHON ;
1464
+ }
1465
+ }
1466
+
1467
+ if (0 == _compare (env -> architecture , -1 , L"32bit" , -1 )) {
1468
+ size_t tagLength = wcslen (env -> tag );
1469
+ if (tagLength <= 3 || 0 != _compare (& env -> tag [tagLength - 3 ], 3 , L"-32" , 3 )) {
1470
+ const wchar_t * rawTag = env -> tag ;
1471
+ wchar_t * realTag = (wchar_t * ) malloc (sizeof (wchar_t ) * (tagLength + 4 ));
1472
+ if (!realTag ) {
1473
+ return RC_NO_MEMORY ;
1474
+ }
1475
+
1476
+ int count = swprintf_s (realTag , tagLength + 4 , L"%s-32" , env -> tag );
1477
+ if (count == -1 ) {
1478
+ free (realTag );
1479
+ return RC_INTERNAL_ERROR ;
1480
+ }
1481
+
1482
+ env -> tag = realTag ;
1483
+ free ((void * )rawTag );
1484
+ }
1485
+ }
1486
+
1487
+ wchar_t buffer [MAXLEN ];
1488
+ if (swprintf_s (buffer , MAXLEN , L"Python %s" , env -> tag )) {
1489
+ copyWstr (& env -> displayName , buffer );
1490
+ }
1491
+
1492
+ return 0 ;
1493
+ }
1494
+
1495
+
1395
1496
int
1396
1497
_registryReadEnvironment (const SearchInfo * search , HKEY root , EnvironmentInfo * env , const wchar_t * fallbackArch )
1397
1498
{
@@ -1403,6 +1504,10 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
1403
1504
return RC_NO_PYTHON ;
1404
1505
}
1405
1506
1507
+ if (_isLegacyVersion (env )) {
1508
+ return _registryReadLegacyEnvironment (search , root , env , fallbackArch );
1509
+ }
1510
+
1406
1511
// If pythonw.exe requested, check specific value
1407
1512
if (search -> windowed ) {
1408
1513
exitCode = _registryReadString (& env -> executablePath , root , L"InstallPath" , L"WindowedExecutablePath" );
@@ -1425,6 +1530,11 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
1425
1530
return exitCode ;
1426
1531
}
1427
1532
1533
+ if (!env -> executablePath ) {
1534
+ debug (L"# %s/%s has no executable path\n" , env -> company , env -> tag );
1535
+ return RC_NO_PYTHON ;
1536
+ }
1537
+
1428
1538
exitCode = _registryReadString (& env -> architecture , root , NULL , L"SysArchitecture" );
1429
1539
if (exitCode ) {
1430
1540
return exitCode ;
@@ -1435,29 +1545,6 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
1435
1545
return exitCode ;
1436
1546
}
1437
1547
1438
- // Only PythonCore entries will infer executablePath from installDir and architecture from the binary
1439
- if (0 == _compare (env -> company , -1 , L"PythonCore" , -1 )) {
1440
- if (!env -> executablePath ) {
1441
- exitCode = _combineWithInstallDir (
1442
- & env -> executablePath ,
1443
- env -> installDir ,
1444
- search -> executable ,
1445
- search -> executableLength
1446
- );
1447
- if (exitCode ) {
1448
- return exitCode ;
1449
- }
1450
- }
1451
- if (!env -> architecture && env -> executablePath && fallbackArch ) {
1452
- copyWstr (& env -> architecture , fallbackArch );
1453
- }
1454
- }
1455
-
1456
- if (!env -> executablePath ) {
1457
- debug (L"# %s/%s has no executable path\n" , env -> company , env -> tag );
1458
- return RC_NO_PYTHON ;
1459
- }
1460
-
1461
1548
return 0 ;
1462
1549
}
1463
1550
@@ -1486,7 +1573,7 @@ _registrySearchTags(const SearchInfo *search, EnvironmentInfo **result, HKEY roo
1486
1573
freeEnvironmentInfo (env );
1487
1574
exitCode = 0 ;
1488
1575
} else if (!exitCode ) {
1489
- exitCode = addEnvironmentInfo (result , env );
1576
+ exitCode = addEnvironmentInfo (result , NULL , env );
1490
1577
if (exitCode ) {
1491
1578
freeEnvironmentInfo (env );
1492
1579
if (exitCode == RC_DUPLICATE_ITEM ) {
@@ -1574,7 +1661,7 @@ appxSearch(const SearchInfo *search, EnvironmentInfo **result, const wchar_t *pa
1574
1661
copyWstr (& env -> displayName , buffer );
1575
1662
}
1576
1663
1577
- int exitCode = addEnvironmentInfo (result , env );
1664
+ int exitCode = addEnvironmentInfo (result , NULL , env );
1578
1665
if (exitCode ) {
1579
1666
freeEnvironmentInfo (env );
1580
1667
if (exitCode == RC_DUPLICATE_ITEM ) {
@@ -1612,7 +1699,7 @@ explicitOverrideSearch(const SearchInfo *search, EnvironmentInfo **result)
1612
1699
if (exitCode ) {
1613
1700
goto abort ;
1614
1701
}
1615
- exitCode = addEnvironmentInfo (result , env );
1702
+ exitCode = addEnvironmentInfo (result , NULL , env );
1616
1703
if (exitCode ) {
1617
1704
goto abort ;
1618
1705
}
@@ -1661,7 +1748,7 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result)
1661
1748
if (exitCode ) {
1662
1749
goto abort ;
1663
1750
}
1664
- exitCode = addEnvironmentInfo (result , env );
1751
+ exitCode = addEnvironmentInfo (result , NULL , env );
1665
1752
if (exitCode ) {
1666
1753
goto abort ;
1667
1754
}
0 commit comments