/*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file getenvs.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "getenvs" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "prefix.h" #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the separator #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) #define XM_OS_ENV_SEP ';' #else #define XM_OS_ENV_SEP ':' #endif /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // the user environment #if !defined(TB_CONFIG_OS_WINDOWS) || defined(TB_COMPILER_LIKE_UNIX) extern tb_char_t **environ; #endif /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t xm_os_getenvs_trim(tb_char_t const **sstr, tb_char_t const **estr) { tb_assert(sstr && estr && *sstr && *estr); tb_char_t const *p = *sstr; tb_char_t const *e = *estr; // trim left while (p < e && tb_isspace(*p)) { p++; } // trim right while (e > p && tb_isspace(*(e - 1))) { e--; } // save trimmed string *sstr = p; *estr = e; } static tb_void_t xm_os_getenvs_process_line(lua_State *lua, tb_char_t const *line) { tb_assert_and_check_return(lua && line); tb_size_t n = tb_strlen(line); tb_check_return(n > 0); // find '=' separator tb_char_t const *p = tb_strchr(line, '='); tb_check_return(p); // get key and value parts tb_char_t const *key_start = line; tb_char_t const *key_end = p; tb_char_t const *value_start = p + 1; tb_char_t const *value_end = line + n; // trim key xm_os_getenvs_trim(&key_start, &key_end); if (key_start >= key_end) { return; } // trim value xm_os_getenvs_trim(&value_start, &value_end); // get key and value lengths tb_size_t key_len = key_end - key_start; tb_size_t value_len = value_end > value_start ? value_end - value_start : 0; // handle Windows-specific PATH conversion tb_char_t const *final_key_start = key_start; tb_size_t final_key_len = key_len; #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) if (key_len == 4 && tb_strnicmp(key_start, "path", 4) == 0) { // use "PATH" instead of "path" static tb_char_t const PATH_UPPER[] = "PATH"; final_key_start = PATH_UPPER; final_key_len = 4; } #endif // set key-value pair in Lua table using pushlstring to avoid length limits lua_pushlstring(lua, final_key_start, final_key_len); lua_pushlstring(lua, value_start, value_len); lua_rawset(lua, -3); } tb_int_t xm_os_getenvs(lua_State *lua) { tb_assert_and_check_return_val(lua, 0); // init table lua_newtable(lua); #if defined(TB_CONFIG_OS_WINDOWS) && !defined(TB_COMPILER_LIKE_UNIX) tb_wchar_t const *p = (tb_wchar_t const *)GetEnvironmentStringsW(); if (p) { tb_char_t *data = tb_null; tb_size_t maxn = 0; tb_char_t line[TB_PATH_MAXN]; tb_size_t n = 0; while (*p) { n = tb_wcslen(p); if (n + 1 < tb_arrayn(line)) { if (tb_wtoa(line, p, tb_arrayn(line)) >= 0) { xm_os_getenvs_process_line(lua, line); } } else { if (!data) { maxn = n + 1; data = (tb_char_t *)tb_malloc(maxn); } else if (n >= maxn) { maxn = n + TB_PATH_MAXN + 1; data = (tb_char_t *)tb_ralloc(data, maxn); } tb_assert_and_check_break(data); if (tb_wtoa(data, p, maxn) >= 0) { xm_os_getenvs_process_line(lua, data); } } p += n + 1; } if (data && data != line) { tb_free(data); } data = tb_null; } #else tb_char_t const **p = (tb_char_t const **)environ; if (p) { while (*p) { xm_os_getenvs_process_line(lua, *p); p++; } } #endif return 1; }