1 /* 2 * environ.c 3 * 4 * ReactOS MSVCRT.DLL Compatibility Library 5 */ 6 7 #include <precomp.h> 8 #include <internal/wine/msvcrt.h> 9 10 unsigned int _osplatform = 0; 11 unsigned int _osver = 0; 12 unsigned int _winminor = 0; 13 unsigned int _winmajor = 0; 14 unsigned int _winver = 0; 15 16 unsigned int __setlc_active = 0; 17 unsigned int __unguarded_readlc_active = 0; 18 char *_acmdln = NULL; /* pointer to ascii command line */ 19 wchar_t *_wcmdln = NULL; /* pointer to wide character command line */ 20 #undef _environ 21 #undef _wenviron 22 char **_environ = NULL; /* pointer to environment block */ 23 wchar_t **_wenviron = NULL; /* pointer to environment block */ 24 char **__initenv = NULL; /* pointer to initial environment block */ 25 wchar_t **__winitenv = NULL; /* pointer to initial environment block */ 26 #undef _pgmptr 27 char *_pgmptr = NULL; /* pointer to program name */ 28 #undef _wpgmptr 29 wchar_t *_wpgmptr = NULL; /* pointer to program name */ 30 int __app_type = _UNKNOWN_APP; /* application type */ 31 int _commode; 32 33 34 int BlockEnvToEnvironA(void) 35 { 36 char *ptr, *environment_strings; 37 char **envptr; 38 int count = 1; 39 size_t len; 40 41 TRACE("BlockEnvToEnvironA()\n"); 42 43 environment_strings = GetEnvironmentStringsA(); 44 if (environment_strings == NULL) { 45 return -1; 46 } 47 48 for (ptr = environment_strings; *ptr; ptr += len) 49 { 50 len = strlen(ptr) + 1; 51 /* Skip drive letter settings. */ 52 if (*ptr != '=') 53 count++; 54 } 55 56 __initenv = _environ = malloc(count * sizeof(char*)); 57 if (_environ) 58 { 59 for (ptr = environment_strings, envptr = _environ; count > 1; ptr += len) 60 { 61 len = strlen(ptr) + 1; 62 /* Skip drive letter settings. */ 63 if (*ptr != '=') 64 { 65 if ((*envptr = malloc(len)) == NULL) 66 { 67 for (envptr--; envptr >= _environ; envptr--) 68 free(*envptr); 69 FreeEnvironmentStringsA(environment_strings); 70 free(_environ); 71 __initenv = _environ = NULL; 72 return -1; 73 } 74 memcpy(*envptr++, ptr, len); 75 count--; 76 } 77 } 78 /* Add terminating NULL entry. */ 79 *envptr = NULL; 80 } 81 82 FreeEnvironmentStringsA(environment_strings); 83 return _environ ? 0 : -1; 84 } 85 86 int BlockEnvToEnvironW(void) 87 { 88 wchar_t *ptr, *environment_strings; 89 wchar_t **envptr; 90 int count = 1; 91 size_t len; 92 93 TRACE("BlockEnvToEnvironW()\n"); 94 95 environment_strings = GetEnvironmentStringsW(); 96 if (environment_strings == NULL) { 97 return -1; 98 } 99 100 for (ptr = environment_strings; *ptr; ptr += len) 101 { 102 len = wcslen(ptr) + 1; 103 /* Skip drive letter settings. */ 104 if (*ptr != '=') 105 count++; 106 } 107 108 __winitenv = _wenviron = malloc(count * sizeof(wchar_t*)); 109 if (_wenviron) 110 { 111 for (ptr = environment_strings, envptr = _wenviron; count > 1; ptr += len) 112 { 113 len = wcslen(ptr) + 1; 114 /* Skip drive letter settings. */ 115 if (*ptr != '=') 116 { 117 if ((*envptr = malloc(len * sizeof(wchar_t))) == NULL) 118 { 119 for (envptr--; envptr >= _wenviron; envptr--) 120 free(*envptr); 121 FreeEnvironmentStringsW(environment_strings); 122 free(_wenviron); 123 __winitenv = _wenviron = NULL; 124 return -1; 125 } 126 memcpy(*envptr++, ptr, len * sizeof(wchar_t)); 127 count--; 128 } 129 } 130 /* Add terminating NULL entry. */ 131 *envptr = NULL; 132 } 133 134 FreeEnvironmentStringsW(environment_strings); 135 return _wenviron ? 0 : -1; 136 } 137 138 /** 139 * Internal function to duplicate environment block. Although it's 140 * parameter are defined as char**, it's able to work also with 141 * wide character environment block which are of type wchar_t**. 142 * 143 * @param original_environment 144 * Environment to duplicate. 145 * @param wide 146 * Set to zero for multibyte environments, non-zero otherwise. 147 * 148 * @return Original environment in case of failure, otherwise 149 * pointer to new environment block. 150 */ 151 char **DuplicateEnvironment(char **original_environment, int wide) 152 { 153 int count = 1; 154 char **envptr, **newenvptr, **newenv; 155 156 for (envptr = original_environment; *envptr != NULL; envptr++, count++) 157 ; 158 159 newenvptr = newenv = malloc(count * sizeof(char*)); 160 if (newenv == NULL) 161 return original_environment; 162 163 for (envptr = original_environment; count > 1; newenvptr++, count--) 164 { 165 if (wide) 166 *newenvptr = (char*)_wcsdup((wchar_t*)*envptr++); 167 else 168 *newenvptr = _strdup(*envptr++); 169 if (*newenvptr == NULL) 170 { 171 for (newenvptr--; newenvptr >= newenv; newenvptr--) 172 free(*newenvptr); 173 free(newenv); 174 return original_environment; 175 } 176 } 177 *newenvptr = NULL; 178 179 return newenv; 180 } 181 182 /** 183 * Internal function to deallocate environment block. Although it's 184 * parameter are defined as char**, it's able to work also with 185 * wide character environment block which are of type wchar_t**. 186 * 187 * @param environment 188 * Environment to free. 189 */ 190 void FreeEnvironment(char **environment) 191 { 192 char **envptr; 193 for (envptr = environment; *envptr != NULL; envptr++) 194 free(*envptr); 195 free(environment); 196 } 197 198 /** 199 * Internal version of _wputenv and _putenv. It works duplicates the 200 * original envirnments created during initilization if needed to prevent 201 * having spurious pointers floating around. Then it updates the internal 202 * environment tables (_environ and _wenviron) and at last updates the 203 * OS environemnt. 204 * 205 * Note that there can happen situation when the internal [_w]environ 206 * arrays will be updated, but the OS environment update will fail. In 207 * this case we don't undo the changes to the [_w]environ tables to 208 * comply with the Microsoft behaviour (and it's also much easier :-). 209 */ 210 int SetEnv(const wchar_t *option) 211 { 212 wchar_t *epos, *name; 213 wchar_t **wenvptr; 214 wchar_t *woption; 215 char *mboption; 216 int remove, index, count, size, result = 0, found = 0; 217 wchar_t **wnewenv; 218 char **mbnewenv; 219 220 if (option == NULL || (epos = wcschr(option, L'=')) == NULL) 221 return -1; 222 remove = (epos[1] == 0); 223 224 /* Duplicate environment if needed. */ 225 if (_environ == __initenv) 226 { 227 if ((_environ = DuplicateEnvironment(_environ, 0)) == __initenv) 228 return -1; 229 } 230 if (_wenviron == __winitenv) 231 { 232 if ((_wenviron = (wchar_t**)DuplicateEnvironment((char**)_wenviron, 1)) == 233 __winitenv) 234 return -1; 235 } 236 237 /* Create a copy of the option name. */ 238 name = malloc((epos - option + 1) * sizeof(wchar_t)); 239 if (name == NULL) 240 return -1; 241 memcpy(name, option, (epos - option) * sizeof(wchar_t)); 242 name[epos - option] = 0; 243 244 /* Find the option we're trying to modify. */ 245 for (index = 0, wenvptr = _wenviron; *wenvptr != NULL; wenvptr++, index++) 246 { 247 if (!_wcsnicmp(*wenvptr, option, epos - option)) 248 { 249 found = 1; 250 break; 251 } 252 } 253 254 if (remove) 255 { 256 if (!found) 257 { 258 free(name); 259 return 0; 260 } 261 262 /* Remove the option from wide character environment. */ 263 free(*wenvptr); 264 for (count = index; *wenvptr != NULL; wenvptr++, count++) 265 *wenvptr = *(wenvptr + 1); 266 wnewenv = realloc(_wenviron, count * sizeof(wchar_t*)); 267 if (wnewenv != NULL) 268 _wenviron = wnewenv; 269 270 /* Remove the option from multibyte environment. We assume 271 * the environments are in sync and the option is at the 272 * same position. */ 273 free(_environ[index]); 274 memmove(&_environ[index], &_environ[index+1], (count - index) * sizeof(char*)); 275 mbnewenv = realloc(_environ, count * sizeof(char*)); 276 if (mbnewenv != NULL) 277 _environ = mbnewenv; 278 279 result = SetEnvironmentVariableW(name, NULL) ? 0 : -1; 280 } 281 else 282 { 283 /* Make a copy of the option that we will store in the environment block. */ 284 woption = _wcsdup((wchar_t*)option); 285 if (woption == NULL) 286 { 287 free(name); 288 return -1; 289 } 290 291 /* Create a multibyte copy of the option. */ 292 size = WideCharToMultiByte(CP_ACP, 0, option, -1, NULL, 0, NULL, NULL); 293 mboption = malloc(size); 294 if (mboption == NULL) 295 { 296 free(name); 297 free(woption); 298 return -1; 299 } 300 WideCharToMultiByte(CP_ACP, 0, option, -1, mboption, size, NULL, NULL); 301 302 if (found) 303 { 304 /* Replace the current entry. */ 305 free(*wenvptr); 306 *wenvptr = woption; 307 free(_environ[index]); 308 _environ[index] = mboption; 309 } 310 else 311 { 312 /* Get the size of the original environment. */ 313 for (count = index; *wenvptr != NULL; wenvptr++, count++) 314 ; 315 316 /* Create a new entry. */ 317 if ((wnewenv = realloc(_wenviron, (count + 2) * sizeof(wchar_t*))) == NULL) 318 { 319 free(name); 320 free(mboption); 321 free(woption); 322 return -1; 323 } 324 _wenviron = wnewenv; 325 if ((mbnewenv = realloc(_environ, (count + 2) * sizeof(char*))) == NULL) 326 { 327 free(name); 328 free(mboption); 329 free(woption); 330 return -1; 331 } 332 _environ = mbnewenv; 333 334 /* Set the last entry to our option. */ 335 _wenviron[count] = woption; 336 _environ[count] = mboption; 337 _wenviron[count + 1] = NULL; 338 _environ[count + 1] = NULL; 339 } 340 341 /* And finally update the OS environment. */ 342 result = SetEnvironmentVariableW(name, epos + 1) ? 0 : -1; 343 } 344 free(name); 345 346 return result; 347 } 348 349 /* 350 * @implemented 351 */ 352 int *__p__commode(void) // not exported by NTDLL 353 { 354 return &_commode; 355 } 356 357 /* 358 * @implemented 359 */ 360 void __set_app_type(int app_type) 361 { 362 __app_type = app_type; 363 } 364 365 /* 366 * @implemented 367 */ 368 char **__p__acmdln(void) 369 { 370 return &_acmdln; 371 } 372 373 /* 374 * @implemented 375 */ 376 wchar_t **__p__wcmdln(void) 377 { 378 return &_wcmdln; 379 } 380 381 /* 382 * @implemented 383 */ 384 char ***__p__environ(void) 385 { 386 return &_environ; 387 } 388 389 /* 390 * @implemented 391 */ 392 wchar_t ***__p__wenviron(void) 393 { 394 return &_wenviron; 395 } 396 397 /* 398 * @implemented 399 */ 400 char ***__p___initenv(void) 401 { 402 return &__initenv; 403 } 404 405 /* 406 * @implemented 407 */ 408 wchar_t ***__p___winitenv(void) 409 { 410 return &__winitenv; 411 } 412 413 /* 414 * @implemented 415 */ 416 errno_t _get_osplatform(unsigned int *pValue) 417 { 418 if (!MSVCRT_CHECK_PMT(pValue != NULL)) { 419 *_errno() = EINVAL; 420 return EINVAL; 421 } 422 423 *pValue = _osplatform; 424 return 0; 425 } 426 427 /* 428 * @implemented 429 */ 430 int *__p___mb_cur_max(void) 431 { 432 return &get_locinfo()->mb_cur_max; 433 } 434 435 /********************************************************************* 436 * ___mb_cur_max_func(MSVCRT.@) 437 */ 438 int CDECL ___mb_cur_max_func(void) 439 { 440 return get_locinfo()->mb_cur_max; 441 } 442 443 /* 444 * @implemented 445 */ 446 unsigned int *__p__osver(void) 447 { 448 return &_osver; 449 } 450 451 /* 452 * @implemented 453 */ 454 char **__p__pgmptr(void) 455 { 456 return &_pgmptr; 457 } 458 459 /* 460 * @implemented 461 */ 462 int _get_pgmptr(char** p) 463 { 464 if (!MSVCRT_CHECK_PMT(p)) 465 { 466 *_errno() = EINVAL; 467 return EINVAL; 468 } 469 470 *p = _pgmptr; 471 return 0; 472 } 473 474 /* 475 * @implemented 476 */ 477 wchar_t **__p__wpgmptr(void) 478 { 479 return &_wpgmptr; 480 } 481 482 /* 483 * @implemented 484 */ 485 int _get_wpgmptr(WCHAR** p) 486 { 487 if (!MSVCRT_CHECK_PMT(p)) 488 { 489 *_errno() = EINVAL; 490 return EINVAL; 491 } 492 493 *p = _wpgmptr; 494 return 0; 495 } 496 497 /* 498 * @implemented 499 */ 500 unsigned int *__p__winmajor(void) 501 { 502 return &_winmajor; 503 } 504 505 /* 506 * @implemented 507 */ 508 unsigned int *__p__winminor(void) 509 { 510 return &_winminor; 511 } 512 513 /* 514 * @implemented 515 */ 516 unsigned int *__p__winver(void) 517 { 518 return &_winver; 519 } 520 521 /* EOF */ 522