@@ -1294,34 +1294,34 @@ _compareTag(const wchar_t *x, const wchar_t *y)
12941294
12951295
12961296int
1297- addEnvironmentInfo (EnvironmentInfo * * root , EnvironmentInfo * node )
1297+ addEnvironmentInfo (EnvironmentInfo * * root , EnvironmentInfo * parent , EnvironmentInfo * node )
12981298{
12991299 EnvironmentInfo * r = * root ;
13001300 if (!r ) {
13011301 * root = node ;
1302- node -> parent = NULL ;
1302+ node -> parent = parent ;
13031303 return 0 ;
13041304 }
13051305 // Sort by company name
13061306 switch (_compareCompany (node -> company , r -> company )) {
13071307 case -1 :
1308- return addEnvironmentInfo (& r -> prev , node );
1308+ return addEnvironmentInfo (& r -> prev , r , node );
13091309 case 1 :
1310- return addEnvironmentInfo (& r -> next , node );
1310+ return addEnvironmentInfo (& r -> next , r , node );
13111311 case 0 :
13121312 break ;
13131313 }
13141314 // Then by tag (descending)
13151315 switch (_compareTag (node -> tag , r -> tag )) {
13161316 case -1 :
1317- return addEnvironmentInfo (& r -> next , node );
1317+ return addEnvironmentInfo (& r -> next , r , node );
13181318 case 1 :
1319- return addEnvironmentInfo (& r -> prev , node );
1319+ return addEnvironmentInfo (& r -> prev , r , node );
13201320 case 0 :
13211321 break ;
13221322 }
13231323 // Then keep the one with the lowest internal sort key
1324- if (r -> internalSortKey < node -> internalSortKey ) {
1324+ if (node -> internalSortKey < r -> internalSortKey ) {
13251325 // Replace the current node
13261326 node -> parent = r -> parent ;
13271327 if (node -> parent ) {
@@ -1334,9 +1334,16 @@ addEnvironmentInfo(EnvironmentInfo **root, EnvironmentInfo *node)
13341334 freeEnvironmentInfo (node );
13351335 return RC_INTERNAL_ERROR ;
13361336 }
1337+ } else {
1338+ // If node has no parent, then it is the root.
1339+ * root = node ;
13371340 }
1341+
13381342 node -> next = r -> next ;
13391343 node -> prev = r -> prev ;
1344+
1345+ debug (L"# replaced %s/%s/%i in tree\n" , node -> company , node -> tag , node -> internalSortKey );
1346+ freeEnvironmentInfo (r );
13401347 } else {
13411348 debug (L"# not adding %s/%s/%i to tree\n" , node -> company , node -> tag , node -> internalSortKey );
13421349 return RC_DUPLICATE_ITEM ;
@@ -1392,6 +1399,100 @@ _combineWithInstallDir(const wchar_t **dest, const wchar_t *installDir, const wc
13921399}
13931400
13941401
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+
13951496int
13961497_registryReadEnvironment (const SearchInfo * search , HKEY root , EnvironmentInfo * env , const wchar_t * fallbackArch )
13971498{
@@ -1403,6 +1504,10 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
14031504 return RC_NO_PYTHON ;
14041505 }
14051506
1507+ if (_isLegacyVersion (env )) {
1508+ return _registryReadLegacyEnvironment (search , root , env , fallbackArch );
1509+ }
1510+
14061511 // If pythonw.exe requested, check specific value
14071512 if (search -> windowed ) {
14081513 exitCode = _registryReadString (& env -> executablePath , root , L"InstallPath" , L"WindowedExecutablePath" );
@@ -1425,6 +1530,11 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
14251530 return exitCode ;
14261531 }
14271532
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+
14281538 exitCode = _registryReadString (& env -> architecture , root , NULL , L"SysArchitecture" );
14291539 if (exitCode ) {
14301540 return exitCode ;
@@ -1435,29 +1545,6 @@ _registryReadEnvironment(const SearchInfo *search, HKEY root, EnvironmentInfo *e
14351545 return exitCode ;
14361546 }
14371547
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-
14611548 return 0 ;
14621549}
14631550
@@ -1486,7 +1573,7 @@ _registrySearchTags(const SearchInfo *search, EnvironmentInfo **result, HKEY roo
14861573 freeEnvironmentInfo (env );
14871574 exitCode = 0 ;
14881575 } else if (!exitCode ) {
1489- exitCode = addEnvironmentInfo (result , env );
1576+ exitCode = addEnvironmentInfo (result , NULL , env );
14901577 if (exitCode ) {
14911578 freeEnvironmentInfo (env );
14921579 if (exitCode == RC_DUPLICATE_ITEM ) {
@@ -1574,7 +1661,7 @@ appxSearch(const SearchInfo *search, EnvironmentInfo **result, const wchar_t *pa
15741661 copyWstr (& env -> displayName , buffer );
15751662 }
15761663
1577- int exitCode = addEnvironmentInfo (result , env );
1664+ int exitCode = addEnvironmentInfo (result , NULL , env );
15781665 if (exitCode ) {
15791666 freeEnvironmentInfo (env );
15801667 if (exitCode == RC_DUPLICATE_ITEM ) {
@@ -1612,7 +1699,7 @@ explicitOverrideSearch(const SearchInfo *search, EnvironmentInfo **result)
16121699 if (exitCode ) {
16131700 goto abort ;
16141701 }
1615- exitCode = addEnvironmentInfo (result , env );
1702+ exitCode = addEnvironmentInfo (result , NULL , env );
16161703 if (exitCode ) {
16171704 goto abort ;
16181705 }
@@ -1661,7 +1748,7 @@ virtualenvSearch(const SearchInfo *search, EnvironmentInfo **result)
16611748 if (exitCode ) {
16621749 goto abort ;
16631750 }
1664- exitCode = addEnvironmentInfo (result , env );
1751+ exitCode = addEnvironmentInfo (result , NULL , env );
16651752 if (exitCode ) {
16661753 goto abort ;
16671754 }
0 commit comments