@@ -781,12 +781,157 @@ gethandle(PyObject* obj, const char* name)
781781 return ret ;
782782}
783783
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+
784927static wchar_t *
785928getenvironment (PyObject * environment )
786929{
787930 Py_ssize_t i , envsize , totalsize ;
788931 wchar_t * buffer = NULL , * p , * end ;
789- PyObject * keys , * values ;
932+ PyObject * normalized_environment = NULL ;
933+ PyObject * keys = NULL ;
934+ PyObject * values = NULL ;
790935
791936 /* convert environment dictionary to windows environment string */
792937 if (! PyMapping_Check (environment )) {
@@ -795,11 +940,16 @@ getenvironment(PyObject* environment)
795940 return NULL ;
796941 }
797942
798- keys = PyMapping_Keys (environment );
799- if (! keys ) {
943+ normalized_environment = normalize_environment (environment );
944+ if (normalize_environment == NULL ) {
800945 return NULL ;
801946 }
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 );
803953 if (!values ) {
804954 goto error ;
805955 }
@@ -891,6 +1041,7 @@ getenvironment(PyObject* environment)
8911041
8921042cleanup :
8931043error :
1044+ Py_XDECREF (normalized_environment );
8941045 Py_XDECREF (keys );
8951046 Py_XDECREF (values );
8961047 return buffer ;
0 commit comments