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