@@ -781,12 +781,157 @@ gethandle(PyObject* obj, const char* name)
781
781
return ret ;
782
782
}
783
783
784
+ static PyObject *
785
+ sortenvironmentkey (PyObject * module , PyObject * item )
786
+ {
787
+ return _winapi_LCMapStringEx_impl (NULL , LOCALE_NAME_INVARIANT ,
788
+ LCMAP_UPPERCASE , item );
789
+ }
790
+
791
+ static PyMethodDef sortenvironmentkey_def = {
792
+ "sortenvironmentkey" , _PyCFunction_CAST (sortenvironmentkey ), METH_O , "" ,
793
+ };
794
+
795
+ static int
796
+ sort_environment_keys (PyObject * keys )
797
+ {
798
+ PyObject * keyfunc = PyCFunction_New (& sortenvironmentkey_def , NULL );
799
+ if (keyfunc == NULL ) {
800
+ return -1 ;
801
+ }
802
+ PyObject * kwnames = Py_BuildValue ("(s)" , "key" );
803
+ if (kwnames == NULL ) {
804
+ Py_DECREF (keyfunc );
805
+ return -1 ;
806
+ }
807
+ PyObject * args [] = { keys , keyfunc };
808
+ PyObject * ret = PyObject_VectorcallMethod (& _Py_ID (sort ), args , 1 , kwnames );
809
+ Py_DECREF (keyfunc );
810
+ Py_DECREF (kwnames );
811
+ if (ret == NULL ) {
812
+ return -1 ;
813
+ }
814
+ Py_DECREF (ret );
815
+
816
+ return 0 ;
817
+ }
818
+
819
+ static int
820
+ compare_string_ordinal (PyObject * str1 , PyObject * str2 , int * result )
821
+ {
822
+ wchar_t * s1 = PyUnicode_AsWideCharString (str1 , NULL );
823
+ if (s1 == NULL ) {
824
+ return -1 ;
825
+ }
826
+ wchar_t * s2 = PyUnicode_AsWideCharString (str2 , NULL );
827
+ if (s2 == NULL ) {
828
+ PyMem_Free (s1 );
829
+ return -1 ;
830
+ }
831
+ * result = CompareStringOrdinal (s1 , -1 , s2 , -1 , TRUE);
832
+ PyMem_Free (s1 );
833
+ PyMem_Free (s2 );
834
+ return 0 ;
835
+ }
836
+
837
+ static PyObject *
838
+ dedup_environment_keys (PyObject * keys )
839
+ {
840
+ PyObject * result = PyList_New (0 );
841
+ if (result == NULL ) {
842
+ return NULL ;
843
+ }
844
+
845
+ // Iterate over the pre-ordered keys, check whether the current key is equal
846
+ // to the next key (ignoring case), if different, insert the current value
847
+ // into the result list. If they are equal, do nothing because we always
848
+ // want to keep the last inserted one.
849
+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (keys ); i ++ ) {
850
+ PyObject * key = PyList_GET_ITEM (keys , i );
851
+
852
+ // The last key will always be kept.
853
+ if (i + 1 == PyList_GET_SIZE (keys )) {
854
+ if (PyList_Append (result , key ) < 0 ) {
855
+ Py_DECREF (result );
856
+ return NULL ;
857
+ }
858
+ continue ;
859
+ }
860
+
861
+ PyObject * next_key = PyList_GET_ITEM (keys , i + 1 );
862
+ int compare_result ;
863
+ if (compare_string_ordinal (key , next_key , & compare_result ) < 0 ) {
864
+ Py_DECREF (result );
865
+ return NULL ;
866
+ }
867
+ if (compare_result == CSTR_EQUAL ) {
868
+ continue ;
869
+ }
870
+ if (PyList_Append (result , key ) < 0 ) {
871
+ Py_DECREF (result );
872
+ return NULL ;
873
+ }
874
+ }
875
+
876
+ return result ;
877
+ }
878
+
879
+ static PyObject *
880
+ normalize_environment (PyObject * environment )
881
+ {
882
+ PyObject * keys = PyMapping_Keys (environment );
883
+ if (keys == NULL ) {
884
+ return NULL ;
885
+ }
886
+
887
+ if (sort_environment_keys (keys ) < 0 ) {
888
+ Py_DECREF (keys );
889
+ return NULL ;
890
+ }
891
+
892
+ PyObject * normalized_keys = dedup_environment_keys (keys );
893
+ Py_DECREF (keys );
894
+ if (normalized_keys == NULL ) {
895
+ return NULL ;
896
+ }
897
+
898
+ PyObject * result = PyDict_New ();
899
+ if (result == NULL ) {
900
+ Py_DECREF (normalized_keys );
901
+ return NULL ;
902
+ }
903
+
904
+ for (int i = 0 ; i < PyList_GET_SIZE (normalized_keys ); i ++ ) {
905
+ PyObject * key = PyList_GET_ITEM (normalized_keys , i );
906
+ PyObject * value = PyObject_GetItem (environment , key );
907
+ if (value == NULL ) {
908
+ Py_DECREF (normalized_keys );
909
+ Py_DECREF (result );
910
+ return NULL ;
911
+ }
912
+
913
+ int ret = PyObject_SetItem (result , key , value );
914
+ Py_DECREF (value );
915
+ if (ret < 0 ) {
916
+ Py_DECREF (normalized_keys );
917
+ Py_DECREF (result );
918
+ return NULL ;
919
+ }
920
+ }
921
+
922
+ Py_DECREF (normalized_keys );
923
+
924
+ return result ;
925
+ }
926
+
784
927
static wchar_t *
785
928
getenvironment (PyObject * environment )
786
929
{
787
930
Py_ssize_t i , envsize , totalsize ;
788
931
wchar_t * buffer = NULL , * p , * end ;
789
- PyObject * keys , * values ;
932
+ PyObject * normalized_environment = NULL ;
933
+ PyObject * keys = NULL ;
934
+ PyObject * values = NULL ;
790
935
791
936
/* convert environment dictionary to windows environment string */
792
937
if (! PyMapping_Check (environment )) {
@@ -795,11 +940,16 @@ getenvironment(PyObject* environment)
795
940
return NULL ;
796
941
}
797
942
798
- keys = PyMapping_Keys (environment );
799
- if (! keys ) {
943
+ normalized_environment = normalize_environment (environment );
944
+ if (normalize_environment == NULL ) {
800
945
return NULL ;
801
946
}
802
- values = PyMapping_Values (environment );
947
+
948
+ keys = PyMapping_Keys (normalized_environment );
949
+ if (!keys ) {
950
+ goto error ;
951
+ }
952
+ values = PyMapping_Values (normalized_environment );
803
953
if (!values ) {
804
954
goto error ;
805
955
}
@@ -891,6 +1041,7 @@ getenvironment(PyObject* environment)
891
1041
892
1042
cleanup :
893
1043
error :
1044
+ Py_XDECREF (normalized_environment );
894
1045
Py_XDECREF (keys );
895
1046
Py_XDECREF (values );
896
1047
return buffer ;
0 commit comments