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