Skip to content

Commit

Permalink
Fixed encoding in lua functions.
Browse files Browse the repository at this point in the history
This should resolve issue 415 in mridgers/clink (for almost all of the
lua functions, not just the one specifically mentioned there).

[#415](mridgers/clink#415)
Different encodings in different lua functions
  • Loading branch information
chrisant996 committed Oct 10, 2020
1 parent 9f2c35c commit 99b2b65
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 302 deletions.
3 changes: 2 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,17 @@ Lua support changed significantly. Explore how to support backward compatibilit

### Other
- `match.ignore_case` can't be working correctly, and probably readline settings should determine it.
- `_rl_completion_case_map` isn't supported properly in clink lua APIs, nor in general. _(The 0.4.8 implementation simply converted `-` and `_` to `?` and accepted all matches!)_

## Issues Backlog [clink/issues](https://github.com/mridgers/clink/issues)
- [#502](https://github.com/mridgers/clink/issues/502) Error in folders containing [ ] characters
- [#415](https://github.com/mridgers/clink/issues/415) Different encodings in different lua functions
- [#544](https://github.com/mridgers/clink/issues/544) Clink v1.0.0.a1 doesn't support cyrillic characters keyboard input

## Questions
- What is `set-mark`?
- How does `reverse-search-history` work?
- How does `kill-line` work?
- What to do about `MODE4` in the code base?

<br>
<br>
Expand Down
293 changes: 17 additions & 276 deletions clink/lua/src/clink_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <core/base.h>
#include <core/path.h>
#include <core/str.h>
#include <core/os.h>

// BEGIN -- Clink 0.4.8 API compatibility --------------------------------------

Expand All @@ -23,19 +24,6 @@ extern int g_slash_translation;
#endif
extern int lua_execute(lua_State* state);

//------------------------------------------------------------------------------
static int change_dir(lua_State* state)
{
// Check we've got at least one string argument.
if (lua_gettop(state) == 0 || !lua_isstring(state, 1))
return 0;

const char* path = lua_tostring(state, 1);
SetCurrentDirectory(path);

return 0;
}

//------------------------------------------------------------------------------
static int to_lowercase(lua_State* state)
{
Expand Down Expand Up @@ -92,72 +80,6 @@ static int to_lowercase(lua_State* state)
return 1;
}

//------------------------------------------------------------------------------
static int find_files_impl(lua_State* state, int dirs_only)
{
// Check arguments.
int i = lua_gettop(state);
if (i == 0 || lua_isnil(state, 1))
return 0;

const char* mask = lua_tostring(state, 1);

// Should the mask be adjusted for -/_ case mapping?
str<512> buffer;
if (_rl_completion_case_map && i > 1 && lua_toboolean(state, 2))
{
buffer << mask;
mask = buffer.c_str();

char* slash;
slash = strrchr(buffer.data(), '\\');
slash = slash ? slash : strrchr(buffer.data(), '/');
slash = slash ? slash + 1 : buffer.data();

while (*slash)
{
char c = *slash;
if (c == '_' || c == '-')
*slash = '?';

++slash;
}
}

lua_createtable(state, 0, 0);

i = 1;
WIN32_FIND_DATA fd;
HANDLE h = FindFirstFile(mask, &fd);
if (h != INVALID_HANDLE_VALUE)
{
do
{
if (dirs_only && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
continue;

lua_pushstring(state, fd.cFileName);
lua_rawseti(state, -2, i++);
}
while (FindNextFile(h, &fd));
FindClose(h);
}

return 1;
}

//------------------------------------------------------------------------------
static int find_files(lua_State* state)
{
return find_files_impl(state, 0);
}

//------------------------------------------------------------------------------
static int find_dirs(lua_State* state)
{
return find_files_impl(state, 1);
}

//------------------------------------------------------------------------------
static int matches_are_files(lua_State* state)
{
Expand All @@ -172,103 +94,6 @@ static int matches_are_files(lua_State* state)
return 0;
}

//------------------------------------------------------------------------------
static char* mbcs_to_utf8(char* buff)
{
wchar_t* buf_wchar;
char* buf_utf8;
int len_wchar, len_utf8;

// Convert MBCS to WideChar.
len_wchar = MultiByteToWideChar(CP_ACP, 0, buff, -1, NULL, 0);
buf_wchar = (wchar_t*)malloc((len_wchar + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, 0, buff, -1, buf_wchar, len_wchar);

// Convert WideChar to UTF8.
len_utf8 = WideCharToMultiByte(CP_UTF8, 0, buf_wchar, len_wchar, NULL, 0, NULL, NULL);
buf_utf8 = (char*)malloc(len_utf8 + 1);
WideCharToMultiByte(CP_UTF8, 0, buf_wchar, len_wchar, buf_utf8, len_utf8, NULL, NULL);

free(buf_wchar);
return buf_utf8;
}

//------------------------------------------------------------------------------
static int get_env(lua_State* state)
{
unsigned size;
const char* name;
char* buffer;
char* buf_utf8;

if (lua_gettop(state) == 0)
{
return 0;
}

if (lua_isnil(state, 1))
{
return 0;
}

name = lua_tostring(state, 1);
size = GetEnvironmentVariable(name, nullptr, 0);
if (!size)
{
return 0;
}

buffer = (char*)malloc(size);
GetEnvironmentVariable(name, buffer, size);
buf_utf8 = mbcs_to_utf8(buffer);
lua_pushstring(state, buf_utf8);
free(buf_utf8);
free(buffer);

return 1;
}

//------------------------------------------------------------------------------
static int get_env_var_names(lua_State* state)
{
char* env_strings;
int i = 1;

lua_createtable(state, 0, 0);
env_strings = GetEnvironmentStrings();
if (env_strings != nullptr)
{
char* string = env_strings;

while (*string)
{
char* eq = strchr(string, L'=');
if (eq != nullptr)
{
size_t length = eq - string + 1;
char name[1024];

length = length < sizeof_array(name) ? length : sizeof_array(name);
--length;
if (length > 0)
{
strncpy(name, string, length);
name[length] = L'\0';

lua_pushstring(state, name);
lua_rawseti(state, -2, i++);
}
}

string += strlen(string) + 1;
}

FreeEnvironmentStrings(env_strings);
}

return 1;
}

//------------------------------------------------------------------------------
static int get_setting_str(lua_State* state)
{
Expand Down Expand Up @@ -316,36 +141,6 @@ static int slash_translation(lua_State* state)
}
#endif

//------------------------------------------------------------------------------
static int is_dir(lua_State* state)
{
const char* name;
DWORD attrib;
int i;

if (lua_gettop(state) == 0)
{
return 0;
}

if (lua_isnil(state, 1))
{
return 0;
}

i = 0;
name = lua_tostring(state, 1);
attrib = GetFileAttributes(name);
if (attrib != INVALID_FILE_ATTRIBUTES)
{
i = !!(attrib & FILE_ATTRIBUTE_DIRECTORY);
}

lua_pushboolean(state, i);

return 1;
}

//------------------------------------------------------------------------------
static int get_rl_variable(lua_State* state)
{
Expand Down Expand Up @@ -393,70 +188,6 @@ static int get_host_process(lua_State* state)
return 1;
}

//------------------------------------------------------------------------------
static int get_cwd(lua_State* state)
{
char path[MAX_PATH];

GetCurrentDirectory(sizeof_array(path), path);
lua_pushstring(state, path);
return 1;
}

//------------------------------------------------------------------------------
static int get_console_aliases(lua_State* state)
{
do
{
int i;
int buffer_size;
char* alias;

lua_createtable(state, 0, 0);

#if !defined(__MINGW32__) && !defined(__MINGW64__)
// Get the aliases (aka. doskey macros).
buffer_size = GetConsoleAliasesLength((char*)rl_readline_name);
if (buffer_size == 0)
{
break;
}

char* buffer = (char*)malloc(buffer_size + 1);
if (GetConsoleAliases(buffer, buffer_size, (char*)rl_readline_name) == 0)
{
break;
}

buffer[buffer_size] = '\0';

// Parse the result into a lua table.
alias = buffer;
i = 1;
while (*alias != '\0')
{
char* c = strchr(alias, '=');
if (c == nullptr)
{
break;
}

*c = '\0';
lua_pushstring(state, alias);
lua_rawseti(state, -2, i++);

++c;
alias = c + strlen(c) + 1;
}

free(buffer);
#endif // !__MINGW32__ && !__MINGW64__
}
while (0);

return 1;
}

// END -- Clink 0.4.8 API compatibility ----------------------------------------


Expand Down Expand Up @@ -505,6 +236,16 @@ static int get_screen_info(lua_State* state)
return 1;
}

//------------------------------------------------------------------------------
extern int set_current_dir(lua_State* state);
extern int glob_dirs(lua_State* state);
extern int glob_files(lua_State* state);
extern int get_aliases(lua_State* state);
extern int get_current_dir(lua_State* state);
extern int get_env(lua_State* state);
extern int get_env_names(lua_State* state);
extern int is_dir(lua_State* state);

//------------------------------------------------------------------------------
void clink_lua_initialise(lua_state& lua)
{
Expand All @@ -514,14 +255,14 @@ void clink_lua_initialise(lua_state& lua)
} methods[] = {
// Clink 0.4.8 API compatibility. Clink 1.0.0a1 moved these APIs away
// from "clink.", but backward compatibility requires them here as well.
{ "chdir", &change_dir },
{ "chdir", &set_current_dir },
{ "execute", &lua_execute },
{ "find_dirs", &find_dirs },
{ "find_files", &find_files },
{ "get_console_aliases", &get_console_aliases },
{ "get_cwd", &get_cwd },
{ "find_dirs", &glob_dirs },
{ "find_files", &glob_files },
{ "get_console_aliases", &get_aliases },
{ "get_cwd", &get_current_dir },
{ "get_env", &get_env },
{ "get_env_var_names", &get_env_var_names },
{ "get_env_var_names", &get_env_names },
{ "get_host_process", &get_host_process },
{ "get_rl_variable", &get_rl_variable },
{ "get_screen_info", &get_screen_info },
Expand Down
Loading

0 comments on commit 99b2b65

Please sign in to comment.