@@ -1174,6 +1174,147 @@ static char *path_lookup(const char *cmd, int exe_only)
1174
1174
return prog ;
1175
1175
}
1176
1176
1177
+ #if defined(_MSC_VER )
1178
+
1179
+ /* We need a stable sort */
1180
+ #ifndef INTERNAL_QSORT
1181
+ #include "qsort.c"
1182
+ #endif
1183
+
1184
+ /* Compare only keys */
1185
+ static int wenvcmp (const void * a , const void * b )
1186
+ {
1187
+ wchar_t * p = * (wchar_t * * )a , * q = * (wchar_t * * )b ;
1188
+ size_t p_len , q_len ;
1189
+ int ret ;
1190
+
1191
+ /* Find end of keys */
1192
+ for (p_len = 0 ; p [p_len ] && p [p_len ] != L'=' ; p_len ++ )
1193
+ ; /* do nothing */
1194
+ for (q_len = 0 ; q [q_len ] && q [q_len ] != L'=' ; q_len ++ )
1195
+ ; /* do nothing */
1196
+
1197
+ /* Are keys identical (modulo case)? */
1198
+ if (p_len == q_len && !_wcsnicmp (p , q , p_len ))
1199
+ return 0 ;
1200
+
1201
+ ret = _wcsnicmp (p , q , p_len < q_len ? p_len : q_len );
1202
+ return ret ? ret : (p_len < q_len ? -1 : +1 );
1203
+ }
1204
+
1205
+ /*
1206
+ * Build an environment block combining the inherited environment
1207
+ * merged with the given list of settings.
1208
+ *
1209
+ * Values of the form "KEY=VALUE" in deltaenv override inherited values.
1210
+ * Values of the form "KEY" in deltaenv delete inherited values.
1211
+ *
1212
+ * Multiple entries in deltaenv for the same key are explicitly allowed.
1213
+ *
1214
+ * We return a contiguous block of UNICODE strings with a final trailing
1215
+ * zero word.
1216
+ */
1217
+ static wchar_t * make_environment_block (char * * deltaenv )
1218
+ {
1219
+ /*
1220
+ * The CRT (at least as of UCRT) secretly declares "_wenviron"
1221
+ * as a function that returns a pointer to a mostly static table.
1222
+ * Grab the pointer and cache it for the duration of our loop.
1223
+ */
1224
+ const wchar_t * wenv = GetEnvironmentStringsW (), * p ;
1225
+ size_t delta_size = 0 , size = 1 ; /* for extra NUL at the end */
1226
+
1227
+ wchar_t * * array = NULL ;
1228
+ size_t alloc = 0 , nr = 0 , i ;
1229
+
1230
+ const char * p2 ;
1231
+ wchar_t * wdeltaenv ;
1232
+
1233
+ wchar_t * result , * p3 ;
1234
+
1235
+ /*
1236
+ * If there is no deltaenv to apply, simply return a copy
1237
+ */
1238
+ if (!deltaenv || !* deltaenv ) {
1239
+ for (p = wenv ; p && * p ; ) {
1240
+ size_t s = wcslen (p ) + 1 ;
1241
+ size += s ;
1242
+ p += s ;
1243
+ }
1244
+
1245
+ ALLOC_ARRAY (result , size );
1246
+ memcpy (result , wenv , size * sizeof (* wenv ));
1247
+ FreeEnvironmentStringsW (wenv );
1248
+ return result ;
1249
+ }
1250
+
1251
+ /*
1252
+ * If there is a deltaenv, let's accumulate all keys into `array`,
1253
+ * sort them using the stable git_qsort() and then copy, skipping
1254
+ * duplicate keys
1255
+ */
1256
+
1257
+ for (p = wenv ; p && * p ; ) {
1258
+ size_t s = wcslen (p ) + 1 ;
1259
+ size += s ;
1260
+ ALLOC_GROW (array , nr + 1 , alloc );
1261
+ array [nr ++ ] = p ;
1262
+ p += s ;
1263
+ }
1264
+
1265
+ /* (over-)assess size needed for wchar version of deltaenv */
1266
+ for (i = 0 ; deltaenv [i ]; i ++ ) {
1267
+ size_t s = strlen (deltaenv [i ]) + 1 ;
1268
+ delta_size += s ;
1269
+ }
1270
+
1271
+ ALLOC_ARRAY (wdeltaenv , delta_size );
1272
+
1273
+ /* convert the deltaenv, appending to array */
1274
+ for (i = 0 , p3 = wdeltaenv ; deltaenv [i ]; i ++ ) {
1275
+ size_t s = strlen (deltaenv [i ]) + 1 , wlen ;
1276
+ wlen = xutftowcs (p3 , deltaenv [i ], s * 2 );
1277
+
1278
+ ALLOC_GROW (array , nr + 1 , alloc );
1279
+ array [nr ++ ] = p3 ;
1280
+
1281
+ p3 += wlen + 1 ;
1282
+ }
1283
+
1284
+ git_qsort (array , nr , sizeof (* array ), wenvcmp );
1285
+ ALLOC_ARRAY (result , size + delta_size );
1286
+
1287
+ for (p3 = result , i = 0 ; i < nr ; i ++ ) {
1288
+ wchar_t * equal = wcschr (array [i ], L'=' );;
1289
+
1290
+ /* Skip "to delete" entry */
1291
+ if (!equal )
1292
+ continue ;
1293
+
1294
+ p = array [i ];
1295
+
1296
+ /* Skip any duplicate */
1297
+ if (i + 1 < nr ) {
1298
+ wchar_t * next = array [i + 1 ];
1299
+ size_t n = equal - p ;
1300
+
1301
+ if (!_wcsnicmp (p , next , n ) && (!next [n ] || next [n ] == L'=' ))
1302
+ continue ;
1303
+ }
1304
+
1305
+ size = wcslen (p ) + 1 ;
1306
+ memcpy (p3 , p , size * sizeof (* p ));
1307
+ p3 += size ;
1308
+ }
1309
+ * p3 = L'\0' ;
1310
+
1311
+ free (array );
1312
+ FreeEnvironmentStringsW (wenv );
1313
+ return result ;
1314
+ }
1315
+
1316
+ #else
1317
+
1177
1318
static int do_putenv (char * * env , const char * name , int size , int free_old );
1178
1319
1179
1320
/* used number of elements of environ array, including terminating NULL */
@@ -1220,6 +1361,7 @@ static wchar_t *make_environment_block(char **deltaenv)
1220
1361
free (tmpenv );
1221
1362
return wenvblk ;
1222
1363
}
1364
+ #endif
1223
1365
1224
1366
static void do_unset_environment_variables (void )
1225
1367
{
@@ -1510,6 +1652,70 @@ int mingw_kill(pid_t pid, int sig)
1510
1652
return -1 ;
1511
1653
}
1512
1654
1655
+ #if defined(_MSC_VER )
1656
+
1657
+ /* UTF8 versions of getenv and putenv (and unsetenv).
1658
+ * Internally, they use the CRT's stock UNICODE routines
1659
+ * to avoid data loss.
1660
+ *
1661
+ * Unlike the mingw version, we DO NOT directly write to
1662
+ * the CRT variables. We also DO NOT try to manage/replace
1663
+ * the CRT storage.
1664
+ */
1665
+ char * msc_getenv (const char * name )
1666
+ {
1667
+ int len_key , len_value ;
1668
+ wchar_t * w_key ;
1669
+ char * value ;
1670
+ const wchar_t * w_value ;
1671
+
1672
+ if (!name || !* name )
1673
+ return NULL ;
1674
+
1675
+ len_key = strlen (name ) + 1 ;
1676
+ w_key = calloc (len_key , sizeof (wchar_t ));
1677
+ xutftowcs (w_key , name , len_key );
1678
+ w_value = _wgetenv (w_key );
1679
+ free (w_key );
1680
+
1681
+ if (!w_value )
1682
+ return NULL ;
1683
+
1684
+ len_value = wcslen (w_value ) * 3 + 1 ;
1685
+ value = calloc (len_value , sizeof (char ));
1686
+ xwcstoutf (value , w_value , len_value );
1687
+
1688
+ /* TODO Warning: We return "value" which is an allocated
1689
+ * value and the caller is NOT expecting to have to free
1690
+ * it, so we leak memory.
1691
+ */
1692
+ return value ;
1693
+ }
1694
+
1695
+ int msc_putenv (const char * name )
1696
+ {
1697
+ int len , result ;
1698
+ char * equal ;
1699
+ wchar_t * wide ;
1700
+
1701
+ if (!name || !* name )
1702
+ return 0 ;
1703
+
1704
+ len = strlen (name );
1705
+ equal = strchr (name , '=' );
1706
+ wide = calloc (len + 1 + !equal , sizeof (wchar_t ));
1707
+ xutftowcs (wide , name , len + 1 );
1708
+ if (!equal )
1709
+ wcscat (wide , L"=" );
1710
+
1711
+ result = _wputenv (wide );
1712
+
1713
+ free (wide );
1714
+ return result ;
1715
+ }
1716
+
1717
+ #else
1718
+
1513
1719
/*
1514
1720
* Compare environment entries by key (i.e. stopping at '=' or '\0').
1515
1721
*/
@@ -1638,6 +1844,8 @@ int mingw_putenv(const char *namevalue)
1638
1844
return 0 ;
1639
1845
}
1640
1846
1847
+ #endif
1848
+
1641
1849
/*
1642
1850
* Note, this isn't a complete replacement for getaddrinfo. It assumes
1643
1851
* that service contains a numerical port, or that it is null. It
0 commit comments