note everything works great if i use Ascii, but:
in my utf8-encoded script i have this:
print "frøânçïé"
in my embedded C++ i have this:
PyObject* CPython_Script::print(PyObject *args)
{
PyObject *resultObjP = NULL;
const char *utf8_strZ = NULL;
if (PyArg_ParseTuple(args, "s", &utf8_strZ)) {
Log(utf8_strZ, false);
resultObjP = Py_None;
Py_INCREF(resultObjP);
}
return resultObjP;
}
Now, i know that my Log() can print utf8 (has for years, very well debugged)
but what it actually prints is this:
print "frøânçïé"
frøânçïé
another method i use looks like this:
kj_commands.menu("控件", "同步滑帧", "全局无滑帧")
or
kj_commands.menu(u"控件", u"同步滑帧", u"全局无滑帧")
and in my C++ i have:
SuperString ScPyObject::GetAs_String()
{
SuperString str;
if (PyUnicode_Check(i_objP)) {
#if 1
// method 1
{
ScPyObject utf8Str(PyUnicode_AsUTF8String(i_objP));
str = utf8Str.GetAs_String();
}
#elif 0
// method 2
{
UTF8Char *uniZ = (UTF8Char *)PyUnicode_AS_UNICODE(i_objP);
str.assign(&uniZ[0], &uniZ[PyUnicode_GET_DATA_SIZE(i_objP)], kCFStringEncodingUTF16);
}
#else
// method 3
{
UTF32Vec charVec(32768); CF_ASSERT(sizeof(UTF32Vec::value_type) == sizeof(wchar_t));
PyUnicodeObject *uniObjP = (PyUnicodeObject *)(i_objP);
Py_ssize_t sizeL(PyUnicode_AsWideChar(uniObjP, (wchar_t *)&charVec[0], charVec.size()));
charVec.resize(sizeL);
charVec.push_back(0);
str.Set(SuperString(&charVec[0]));
}
#endif
} else {
str.Set(uc(PyString_AsString(i_objP)));
}
Log(str.utf8Z());
return str;
}
for the string, "控件", i get:
控件
for the unicode string, u"控件", Methods 1, 2, and 3, i get the same thing:
控件
okay so what am i doing wrong???
Related
I do not know how to pass the value asynchronously to EM_ASM, here's how I try to do it (but JS says it's not a function):
const auto testFunc = [] (const char* data)
{
printf("data: %s\n", data);
}
EM_ASM_(
{
var funcResult = ($0);
var text = "data";
var lengthBytes = lengthBytesUTF8(text) + 1;
var stringOnWasmHeap = _malloc(lengthBytes);
stringToUTF8(text, stringOnWasmHeap, lengthBytes);
// exception thrown: TypeError: funcResult is not a function
funcResult(stringOnWasmHeap);
}, testFunc);
The documentation says that you can use a function (em_str_callback_func) of the em_str_callback_func type. But it doesn't say how to use it.
https://emscripten.org/docs/api_reference/emscripten.h.html
I don't know about passing callbacks, but if what you want to do is to return a value from JS, then the docs have such an example: you have to use EM_ASM_INT instead:
int x = EM_ASM_INT({
console.log('I received: ' + $0);
return $0 + 1;
}, 100);
printf("%d\n", x);
The API reference has another example for returning a string:
char *str = (char*)EM_ASM_INT({
var jsString = 'Hello with some exotic Unicode characters: Tässä on yksi lumiukko: ☃, ole hyvä.';
var lengthBytes = lengthBytesUTF8(jsString)+1;
// 'jsString.length' would return the length of the string as UTF-16
// units, but Emscripten C strings operate as UTF-8.
var stringOnWasmHeap = _malloc(lengthBytes);
stringToUTF8(jsString, stringOnWasmHeap, lengthBytes);
return stringOnWasmHeap;
});
printf("UTF8 string says: %s\n", str);
free(str); // Each call to _malloc() must be paired with free(), or heap memory will leak!
Once you have the value in C you can just call your testfunc directly.
I'd like to valid a string to check if the string just includes valid characters or not using C++.
Valid characters should be given to the function like as charset of valid characters: "abc123".
A string that just includes the characters given in the charset above should return true while a string that also includes other characters then given should return false. Obviously a easy task :)
--> using charset abc123:
string myString_1 = "bbbac1" // should get true
string myString_2 = "bbbac132aacc" // should get true
string myString_3 = "xxxxxx" // should get false
string myString_4 = "bbbac12533cc" // should get false
How can I implement a call like this in C++?
Note: I though about using something like the code below but I'm pretty sure theres a way better solution.
string charset = "abc123";
string myString = "bbbac1";
for (int i=0; i<charset.length(); i++) {
std::replace( myString.begin(), myString.end(), charset[i], '');
}
bool isValid = (myString.length() == 0);
AS igor-tandetnik pointed in comments this is a job for std::find_first_not_of:
auto validate(const std::string& str, const std::string& charset) -> bool
{
return str.find_first_not_of(charset) == std::string::npos;
}
You can write your own check function:
bool checkstring(std::string &checkstring, std::string &legalchars) {
for (char c : checkstring) {
// resetting the bool
bool isLegal = false;
for (char d : legalchars) {
// comparing the chars
if (c == d) { isLegal = true; }
}
// if a non-legal char was found, return false
if (!isLegal) { return false; }
}
// if no non-legal character was found, return true
return true;
}
Although there might be a better alternative using the standard libraries, especially if you need to compare very long strings with a large set of legal characters.
I'm trying to create a function to get a username using a try and catch method in C++. Unfortunately this code doesn't work, and my application closes when it tries to run.
QString UserInfo::getFullUserName()
{
DBG_ENTERFUNC(getFullUserName);
QString result;
qDebug("trying to get the username");
try
{
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
result = fullUserData.pw_gecos;
// it is the first of the comma seperated records that contain the user name
result = result.split(",").first();
if (result.isEmpty())
{
result = getUserName();
}
}
catch (...)
{
qDebug("exception caught");
}
qDebug() << result;
#endif
DBG_EXITFUNC;
return result;
}
The problem occurs in this line of code as I have placed prints after it that are never reached.
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
Does anyone know what is the issue here?
*Edit--------
Here is my function getUserName()
QString UserInfo::GetUserName()
{
DBG_ENTERFUNC(GetUserName);
QString result;
foreach (QString environmentEntry, QProcess::systemEnvironment())
{
QString varName = environmentEntry.section('=',0,0);
QString varValue = environmentEntry.section('=',1,1);
if (varName == "USER" || varName == "USERNAME")
{
result = varValue;
}
}
DBG_EXITFUNC;
return result;
}
getpwnam() returns NULL when the username was not found. You are potentially dereferencing a NULL pointer.
*getpwnam(getUserName().toLatin1());
// ^ potential NULL pointer deref
Always check before deferencing a potentially invalid pointer:
struct passwd *fullUserData = getpwnam(getUserName().toLatin1());
// ^ note pointer
if (fullUserData != NULL) {
result = fullUserData->pw_gecos;
// ^^ fullUserData is a struct pointer
} else {
// throw Exception
}
If this is confusing to you, you might want to read up on C++ and pointers.
My question is nearly identical to this question, except that the linked question deals with char*, whereas I'm using std::string in my code. Like the linked question, I'm also using C# as my target language.
I have a class written in C++:
class MyClass
{
public:
const std::string get_value() const; // returns utf8-string
void set_value(const std::string &value); // sets utf8-string
private:
// ...
};
And this get's wrapped by SWIG in C# as follows:
public class MyClass
{
public string get_value();
public void set_value(string value);
}
SWIG does everything for me, except that it doesn't make an utf8 to utf16 string conversion during the calls to MyClass. My strings come through fine if they are representable in ASCII, but if I try passing a string with non-ascii characters in a round-trip through "set_value" and "get_value", I end up with unintelligible characters.
How can I make SWIG wrap UTF-8 encoded C++ strings in C#? n.b. I'm using std::string, not std::wstring, and not char*.
There's a partial solution on the SWIG sourceforge site, but it deals with char* not std::string, and it uses a (configurable) fixed length buffer.
With the help (read: genius!) of David Jeske in the linked Code Project article, I have finally been able to answer this question.
You'll need this class (from David Jeske's code) in your C# library.
public class UTF8Marshaler : ICustomMarshaler {
static UTF8Marshaler static_instance;
public IntPtr MarshalManagedToNative(object managedObj) {
if (managedObj == null)
return IntPtr.Zero;
if (!(managedObj is string))
throw new MarshalDirectiveException(
"UTF8Marshaler must be used on a string.");
// not null terminated
byte[] strbuf = Encoding.UTF8.GetBytes((string)managedObj);
IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length + 1);
Marshal.Copy(strbuf, 0, buffer, strbuf.Length);
// write the terminating null
Marshal.WriteByte(buffer + strbuf.Length, 0);
return buffer;
}
public unsafe object MarshalNativeToManaged(IntPtr pNativeData) {
byte* walk = (byte*)pNativeData;
// find the end of the string
while (*walk != 0) {
walk++;
}
int length = (int)(walk - (byte*)pNativeData);
// should not be null terminated
byte[] strbuf = new byte[length];
// skip the trailing null
Marshal.Copy((IntPtr)pNativeData, strbuf, 0, length);
string data = Encoding.UTF8.GetString(strbuf);
return data;
}
public void CleanUpNativeData(IntPtr pNativeData) {
Marshal.FreeHGlobal(pNativeData);
}
public void CleanUpManagedData(object managedObj) {
}
public int GetNativeDataSize() {
return -1;
}
public static ICustomMarshaler GetInstance(string cookie) {
if (static_instance == null) {
return static_instance = new UTF8Marshaler();
}
return static_instance;
}
}
Then, in Swig's "std_string.i", on line 24 replace this line:
%typemap(imtype) string "string"
with this line:
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string "string"
and on line 61, replace this line:
%typemap(imtype) const string & "string"
with this line:
%typemap(imtype, inattributes="[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]", outattributes="[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") string & "string"
Lo and behold, everything works. Read the linked article for a good understanding of how this works.
I wrote a simple lua function which uses 'C++' function to execute. As my intention of creating a 'C++' function is to use the same across all lua functions to update the 'C++' variables. It works fine for numbers, but when I tried it for boolean values, it give me exception when convert to string.
Here is my code snippet.
C++ code.
#include <lua.hpp>
/* the Lua interpreter */
lua_State *luaState;
std::map<lua_State *, CLuaTest *> luaFbtlookup;
void CLuaTest::CLuaTest() {
// initialize Lua
luaState = luaL_newstate();
lua_register(luaState, "get_value", get_value); // func to get values
lua_register(luaState, "set_value", set_value); // func to set values
// load Lua base libraries
luaL_openlibs(luaState);
luaL_dofile(luaState, "C:\LuaTest.lua");
luaFbtlookup.insert(make_pair(luaState, this));
}
int get_value(lua_State *L);
int set_value(lua_State *L);
extern "C++" int get_value(lua_State *L)
{
string lightName = lua_tostring(L, 1);
FbTLuaLookup::iterator iter = luaFbtlookup.find(L);
if (iter != luaFbtlookup.end()) {
lua_pushstring(L, iter->second->getValueFrom(lightName).c_str());
return 1; // do not return zero
}
return 1;
}
extern "C++" int set_value(lua_State *L)
{
string lightName = lua_tostring(L, 1);
if (NULL == lua_tostring(L, 2))
{
printf("WARNING : Invalid String Argument / Cannot convert arg#2 to string");
}
else {
string value = lua_tostring(L, 2);
FbTLuaLookup::iterator iter = luaFbtlookup.find(L);
if (iter != luaFbtlookup.end()) {
iter->second->setValueTo(lightName, value);
lua_pushnumber(L, true);
return 1; // do not return zero
}
}
return 1;
}
CLuaTest::ExecuteScript(enum Seq) {
switch(Seq) {
case 0:
lua_getglobal(luaState, "AllLightsOff");
break;
case 1:
lua_getglobal(luaState, "RedLightOn");
break;
case 2:
lua_getglobal(luaState, "AmberLightOn");
break;
case 3:
lua_getglobal(luaState, "GreenLightOn");
break;
}
}
My lua script:
function AllLightsOff
set_value("RedLight", 0)
set_value("AmberLight",0)
set_value("GrenLight",0)
end
function RedLightOn
set_value("RedLight", 1)
set_value("AmberLight",0)
set_value("GrenLight",0)
end
function AmberLightOn
set_value("RedLight", 0)
set_value("AmberLight",1)
set_value("GrenLight",0)
end
function GreenLightOn
set_value("RedLight", 0)
set_value("AmberLight",0)
set_value("GrenLight",1)
end
Things work fine with the above code, but when I tried to change the set value to use boolean values like set_value("RedLight", False) I get warning message printing. Should I need to pass False as string?
Lua doesn't have False, so it simply tries to read global _G["False"] which is of course nil.
It has false keyword, however, but it wouldn't work either: lua_tostring is working only for numbers and strings.
We don't see setValueTo code, so it is hard to guess how it works.
If you simply want to pass bool value to it, use lua_toboolean, but be aware that it treats 0 as true (as Lua in general).
If you want to pass "True" or "False" as strings, then yes, you must write set_value("RedLight", "False")
As a side note, consider reading how to implement lua_CFunction protocol. Now, if get_value can't find lightName, it will return the last passed parameter as its result.