Sorry for such a vague title.
Basically, I am trying to hack a function to suit my needs. But lately I have been working a lot on python and my c++ is bit rusty.
So earlier my function took a
int func(FILE *f)
{ .....
if (fgets(line, MM_MAX_LINE_LENGTH, f) == NULL)
return MM_PREMATURE_EOF;
if (sscanf(line, "%s %s %s %s %s", banner, mtx, crd, data_type,
storage_scheme) != 5)
return MM_PREMATURE_EOF;
}
now instead of this I am directly inputing the string data
int func(std::string *data)
{ .....
// how should I modify this if statment..I want to parse the same file
// but instead it is in form of one giant string
}
Thanks
You can use the same code, just convert the data in the std::string into a C string.
sscanf(data->c_str(), "%s %s %s %s %s", //...);
However, you should consider passing in a const reference, since you are probably not planning on modifying your input data:
int func(const std::string &data) {
//...
if (sscanf(data.c_str(), //...)) {
//...
}
}
Related
I get json text returned from an api call and I run it trough a script JSON Serialization and Deserialization from here https://www.mql5.com/en/code/13663.
My issue is that it only process the first few parts of the json because of what I believe to a linebreak/carriage inside the json structure. I dont get any error message, just an array containing everything before that line break.
I dont want to remove the line breaks inside the text fields in the json, only the returns inside the json structure. It is in the place each time just after {"ok":true,"result":[{"update_id":568022212,
Here is a full section
{"ok":true,"result":[{"update_id":568022212,
"channel_post":{"message_id":436,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},"date":1588899840,"reply_to_message":{"message_id":372,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},"date":1588838583,"text":"A\nGbpusd buy now 1.2360\nSl 1.2280 \nTp open\n","entities":[{"offset":52,"length":11,"type":"mention"}]},"text":"A\n42 pips bookd close\ud83d\udfe2\ud83d\udfe2"}},{"update_id":568022213,
"channel_post":{"message_id":437,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},"date":1588900321,"reply_to_message":{"message_id":435,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},"date":1588893671,"text":"A\nGold buy 1713.3\nSl 1702 \nTp open\nSwing trade"},"text":"Amazon\n60 pips bookd close\ud83d\udfe2\ud83d\udfe2"}},{"update_id":568022214,
"channel_post":{"message_id":438,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},
MQL4 code:
int GetUpdates()
{
if(m_token==NULL)
return(ERR_TOKEN_ISEMPTY);
string out;
string url=StringFormat("%s/bot%s/getUpdates",TELEGRAM_BASE_URL,m_token);
string params=StringFormat("offset=%d",m_update_id);
//---
int res=PostRequest(out,url,params,WEB_TIMEOUT);
if(res==0)
{
Print(StringDecode(out));
//--- parse result
CJAVal js(NULL,jtUNDEF);
bool done=js.Deserialize(out);
if(!done)
return(ERR_JSON_PARSING);
bool ok=js["ok"].ToBool();
if(!ok)
return(ERR_JSON_NOT_OK);
CCustomMessage msg;
int total=ArraySize(js["result"].m_e);
for(int i=0; i<total; i++)
{
CJAVal item=js["result"].m_e[i];
//---
msg.update_id=item["update_id"].ToInt();
//---
msg.message_id=item["message"]["message_id"].ToInt();
msg.message_date=(datetime)item["message"]["date"].ToInt();
//---
msg.message_text=item["message"]["text"].ToStr();
printf((datetime)item["message"]["date"].ToInt());
msg.message_text=StringDecode(msg.message_text);
//---
msg.from_id=item["message"]["from"]["id"].ToInt();
msg.from_first_name=item["message"]["from"]["first_name"].ToStr();
msg.from_first_name=StringDecode(msg.from_first_name);
msg.from_last_name=item["message"]["from"]["last_name"].ToStr();
msg.from_last_name=StringDecode(msg.from_last_name);
msg.from_username=item["message"]["from"]["username"].ToStr();
msg.from_username=StringDecode(msg.from_username);
//---
msg.chat_id=item["message"]["chat"]["id"].ToInt();
msg.chat_first_name=item["message"]["chat"]["first_name"].ToStr();
msg.chat_first_name=StringDecode(msg.chat_first_name);
msg.chat_last_name=item["message"]["chat"]["last_name"].ToStr();
msg.chat_last_name=StringDecode(msg.chat_last_name);
msg.chat_username=item["message"]["chat"]["username"].ToStr();
msg.chat_username=StringDecode(msg.chat_username);
I tried to use the same library, it seems to have a bug with parsing arrays. That is why I used https://www.mql5.com/en/code/11134. It has a disadvantage: you need to delete all the objects, unfortunately; as a result there's plenty of code. But at least it works.
Seems your json has incorrect format, I used to cut it a little.
#include <json1.mqh> //modified version, https://www.mql5.com/en/forum/28928/page5#comment_15766620
//const string post_result=
//{"ok":true,"result":[
//{"update_id":568022212,"channel_post":{"message_id":436,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},
//"date":1588899840,"reply_to_message":{"message_id":372,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},
//"date":1588838583,"text":"A\nGbpusd buy now 1.2360\nSl 1.2280 \nTp open\n","entities":[{"offset":52,"length":11,"type":"mention"}]},"text":"A\n42 pips bookd close\ud83d\udfe2\ud83d\udfe2"}},
//{"update_id":568022213,"channel_post":{"message_id":437,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},
//"date":1588900321,"reply_to_message":{"message_id":435,"chat":{"id":-1001436032340,"title":"FORTUNA","type":"channel"},
//"date":1588893671,"text":"A\nGold buy 1713.3\nSl 1702 \nTp open\nSwing trade"},"text":"Amazon\n60 pips bookd close\ud83d\udfe2\ud83d\udfe2" }}]}
//;
void function()
{
//---
const string post_result=getContent();//ok, you managed to get some string here
JSONParser *parser=new JSONParser();
JSONValue *value=parser.parse(post_result);
delete(parser);
if(CheckPointer(value)==POINTER_INVALID)
{
printf("%i %s: error!",__LINE__,__FILE__);
delete(value);
return;
}
JSONObject *obj=(JSONObject*)value;
const bool isSuccess=obj.getBool("ok");
printf("%i %s: isSuccess=%d",__LINE__,__FILE__,isSuccess);
if(!isSuccess)return;
JSONValue *resultValue=obj.getValue("result");
if(CheckPointer(resultValue)!=POINTER_INVALID)
{
JSONArray *resultValueArray=resultValue;
for(int i=0;i<resultValueArray.size();i++)
{
printf("%i %s: #%d=%s",__LINE__,__FILE__,i,resultValueArray.getObject(i).toString());
//you can work with JSONObject or with string, whatever is more convenient
parseResultLine(resultValueArray.getObject(i));
}
delete(resultValueArray);
}
delete(resultValue);
delete(obj);
}
bool parseResultLine(JSONObject *object)
{
const long update_id=object.getLong("update_id");
JSONObject *channel_post=object.getObject("channel_post");
const long message_id=channel_post.getLong("message_id");
const datetime date=(datetime)channel_post.getInt("date");
const string text=channel_post.getString("text");
printf("%i %s: id=%s, dt=%d/%s, text=%s",__LINE__,__FILE__,IntegerToString(message_id),(int)date,TimeToString(date),text);
JSONObject *chat=channel_post.getObject("chat");
const long chat_id=chat.getLong("id");
const string chat_title=chat.getString("title");
printf("%i %s: chat-> id=%I64d title=%s type=%s",__LINE__,__FILE__,chat_id,chat_title,chat.getString("type"));
JSONObject *reply=channel_post.getObject("reply_to_message");
printf("%i %s: replied: id=%s, date=%s",__LINE__,__FILE__,string(reply.getLong("message_id")),TimeToString(reply.getInt("date")));
return true;
}
I am using Jansson.
bool ConvertJsontoString(string inputText, string& OutText)
{
/* Before doing anything I want to check
if the inputText is a valid json string or not */
}
Why don't you read the documentation where it clearly states:
json_t *json_loads(const char *input, size_t flags, json_error_t *error)
Return value: New reference.
Decodes the JSON string input and returns the array or object it contains,
or NULL on error, in which case error is filled with information about the error.
flags is described above.
Also they even provide an example on how to use this:
root = json_loads(text, 0, &error);
free(text);
if(!root)
{
fprintf(stderr, "error: on line %d: %s\n", error.line, error.text);
return 1;
}
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.
My program contains auto-generated structures. When starting I need to validate them with "server" information - so I can be sure that my auto-generated structures are up to date. Server and local structures are valid if they are of the same size, contain fields with the same name and size (and type ideally should be validated too).
This is what I wrote so far:
void SchemeValidator::Validate(cg_scheme_desc_t* schemedesc, Logger& logger)
{
struct cg_message_desc_t* msgdesc = schemedesc->messages;
while (msgdesc)
{
struct cg_field_desc_t* fielddesc = msgdesc->fields;
char* structName = msgdesc->name;
size_t structSize = msgdesc->size;
logger.Debug("Message %s, block size = %d", structName, structSize);
if (strcmp(structName, "orders")) {
if (sizeof(orders) != structSize) {
printf("Validator error, structure 'orders', local size = %d server size = %d!", sizeof(orders), structSize);
throw std::exception("Validator error, structure 'orders' wrong size!");
}
while (fielddesc)
{
logger.Debug("\tField %s = %s [size=%d, offset=%d]", fielddesc->name, fielddesc->type, fielddesc->size, fielddesc->offset);
if (offsetof(struct orders, fielddesc->name) != fielddesc->offset) {
throw std::exception("orders structure offset wrong");
}
// TODO: validate fielddesc->size == sizeof corresponding field in structure
fielddesc = fielddesc->next;
}
} else {
throw std::exception("Validator error, validation not implemented!");
}
msgdesc = msgdesc->next;
}
}
There are a lot of problems:
I wrote if (strcmp(structName, "orders")) because later i need to use orders in several expressions, including sizeof(orders) and offsetof(struct orders, fielddesc->name). But I have a lot of structures and for each of them I have to copy-paste this block. Can I somehow pass string literal to sizeof and offsetof methods or have desired effect some another way?
offsetof(struct orders, fielddesc->name) doesn't work by same reason - second parameter can not be string literal, I receive error C2039: 'fielddesc' : is not a member of 'orders' error
By the same reason I can validate fielddesc->size.
How can I achieve desired validation without intensive copy-pasting and values hard-coding?
I believe you can accomplish what you want by defining structs with typedefs and using a templated function. The following should replace what you have (obviously not tested)
struct OrderType {
typedef cg_field_desc_t* ListItem;
typedef orders Class;
static const std::string Name;
};
std::string OrderType::Name = "orders";
template <class T>
checkStuff(T::ListItem fielddesc, const char* name, size_t structSize)
{
if (strcmp(name, T::Name.c_str())) {
if (sizeof(T::Class) != structSize) {
printf("Validator error, structure 'orders', local size = %d server size = %d!", sizeof(T::Class), structSize);
throw std::exception("Validator error, structure 'orders' wrong size!");
}
while (fielddesc)
{
logger.Debug("\tField %s = %s [size=%d, offset=%d]", fielddesc->name, fielddesc->type, fielddesc->size, fielddesc->offset);
if (offsetof(T::Class, fielddesc->name) != fielddesc->offset) {
throw std::exception("orders structure offset wrong");
}
// TODO: validate fielddesc->size == sizeof corresponding field in structure
fielddesc = fielddesc->next;
}
} else {
throw std::exception("Validator error, validation not implemented!");
}
}
You then replace your if statement with
checkStuff<OrderType>(fielddesc, name, structSize);
You can extend this to other types by defining new structs
struct OtherType {
typedef some_other_t* ListItem;
typedef bizbaz Class;
static const std::string Name;
};
std::string OtherType::Name = "foobar";
Hello! I am currently working on a text adventure in C++ and could use some help.
What I'm trying to do is let the user input a command like the following:
'go kitchen'
'open door with key'
and make the game react accordingly.
Our teacher gave us the following code (which I have modified) and I'm having difficulty understanding what exactly it is doing and how I can use it to make the game. I modified it so that the user can input strings and it does tokenize the string wonderfully into a verb, object, preposition and object2.
But what I need to do then is somehow compare the input to a list of available commands. This is what I'm having trouble accomplishing at the moment. I am new to programming and need to do this as a homework assignment for my studies. Any help would be much appreciated.
struct command {
char* verb;
char* object;
char* preposition;
char* object2;
};
bool getTokens(char * acInput,
const char token_delimiter,
command * pTargetCommand)
{
char * pCurToken;
pCurToken = strtok (acInput, &token_delimiter);
if (pCurToken == NULL) {
printf("Error: Found no verb");
getchar();
return 1;
}
pTargetCommand->verb = pCurToken;
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken == NULL) {
printf("Error: Found no object");
getchar();
return 1;
}
pTargetCommand->object = pCurToken;
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken != NULL) {
pTargetCommand->preposition = pCurToken;
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken == NULL) {
printf("Error: Found no second object for preposition");
getchar();
return 1;
}
pTargetCommand->object2 = pCurToken;
}
pCurToken = strtok (NULL, &token_delimiter);
if (pCurToken != NULL) {
printf("Error: too many tokens.");
getchar();
return 1;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
char acInput[256];
cin.getline (acInput,256);
command myCommand = { NULL };
int RoomChoice = 0;
printf ("Splitting string \"%s\" into tokens:\n", acInput);
getTokens(acInput, *TOKEN_DELIMITER, &myCommand);
printf ("Verb: %s\n", myCommand.verb);
printf ("object: %s\n", myCommand.object);
printf ("preposition: %s\n", myCommand.preposition);
printf ("object2: %s\n", myCommand.object2);
getchar();
return 0;
}
Without giving too much of your homework assignment away, you'll need to somehow read the list of all available actions into a structure, then compare against that structure.
As a hint, depending on the pattern, that might be a switch() {} statement or a collection like an array.
Consider
switch (myCommand.verb)
Case "go":
In a real-world application, you'd spin up a factory of command objects, then invoke one of those. Here, however, I would suggesting thinking through your control statements.
You cannot do a switch with strings (as you already noted, switch only work with constant numbers)
To do compare strings you can use strcmp, strncmp, or better yet, use String.compare. You should be able to find enough information about them with a Google search.