Extracting JSON text from char response buffer - c

I receive a large chunk of text from my Wi-Fi module.
Which is saved in my response buffer.
char wifiResponseBuffer[500];
The contents can be seen below :
AT+CIPSEND=84
> GET http://api.noteu.co.uk/v1/poll/get/?seria
SEND OK
+IPD,308:{"data":[{"line1":" Facebook Note ","line2":"Nathan Weighill also","line3":" commented on Harry ","line4":" Bailey's photo.","beep":1,"received_time":1424976639},{"line1":" Gmail Message ","line2":"","line3":"Noteu Error","line4":"","beep":1,"received_time":1424976640}],"summary":{"note_count":2}}
OK
OK
Unlink
I have a JSON parser library however need to extract the actual JSON text from the response before it can be parsed. This is at the first occurrence of { and last occurrence of }.
What combination of string functions can I use in C to find the indexes of these characters and then extract the JSON text.
Any help is greatly appreciated,
Jack

strchr is used to find the first occurrence of a character in a string. strrchr finds the last.
Here's a brief example of how you might use these:
int test(void)
{
char wifiResponseBuffer[500];
int wifi_len;
// get the WiFi data, leaving 1 byte for a NUL terminator
wifi_len = get_wifi_response(wifiResponseBuffer, sizeof(wifiResponseBuffer)-1);
if (wifi_len < 0)
return -1; // error
// NUL-terminate to use with strxxx functions
wifiResponseBuffer[wifi_len] = '\0';
// Find start of JSON data
const char *json_start = strchr(wifiResponseBuffer, '{');
if (json_start == NULL)
return -1;
json_start++; // advance past {
// Find end of JSON data
const char *json_end = strchr(json_start, '}');
if (json_end == NULL)
return -1;
// Pass the JSON data to the library
size_t json_len = json_end - json_start;
do_something_with_json_data(json_start, json_len);
}

Related

C Curl 400 Bad Request keyword "on"

I wrote a C Program that calls a webservice with cURL. I started my test by hardcoding the address of the webservice with parameters like this :
http://....php?type=adresse&texte=XYZ
It worked fine so I've tried to concatenate a variable for field texte has shown below but it failed and returned me 400 Bad Request.
We checked the content of the request and there is a keyword "on" in front of the webservice address and I don't know where that come from.
on http://....php?type=adresse&texte=xyz&indDebut=0&indFin=1&epsg=900913&format=json"
char* mystrcat( char* dest, char* src )
{
while (*dest) dest++;
while (*dest++ = *src++);
return --dest;
}
recherche = "G0A3B0";
pcbak_adresse(recherche);
const char * pcbak_adresse(const char *details)
{
...
char * lien;
const char * fin_lien;
lien = "http://....php?type=adresse&texte=";
fin_lien = "&indDebut=0&indFin=1&epsg=900913&format=json";
/*Concatenation function*/
mystrcat(details, fin_lien);
mystrcat(lien, details);
/* Set CURL parameters */
curl_easy_setopt(curlHandler, CURLOPT_URL, lien);
curl_easy_setopt(curlHandler, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(curlHandler, CURLOPT_WRITEFUNCTION, callback_func);
curl_easy_setopt(curlHandler, CURLOPT_WRITEDATA, &str);
res = curl_easy_perform(curlHandler);
/* Check for errors */
if (res != CURLE_OK)
return curl_easy_strerror(res);
...
}
Thanks for your help!
No matter what mystrcat() is,
mystrcat(lien, details);
is wrong.
If it creates a new string composed by the two inputs, it's not being captured anywhere.
If it tries to write to lien it's undefined behavior. Because you cannot modify string literals which is what lien is.
The same reasoning probably applies to details, but you didn't post details declaration and/or definition.
Do not use anything like strcat() except if you want to do it only once.
To concatenate strings use something like a structure where you store the length of the current string, the size of the target array, and of course the target array. You can then resize the target when you need to, you don't need to find the end of the target string every time (which is what strcat() will do), you also have the advantage of controlling how you append to the string with a lot of detail.
To achieve what you want, you can do this
char lien[256];
int length;
length = snprintf(
lien,
sizeof(lien),
"http://....php?type=adresse&texte=%s&indDebut=0&indFin=1&epsg=900913&format=json",
details
);
if ((length >= sizeof(lien)) || (length == -1))
return error_occurred_here();
Also, returning a static string (which probably is what curl_easy_strerror() returns), and a tentatively dynamic one from the same function is bad design, because,
You can't tell whether it's an error or the JSON returned from the link.
You will need some method to determine whether it's a static string or the one generated in the function in order to free() it.

strcat not prepending strings in C

I'm working on an apache module that converts groups of slashes into single slashes in order to avoid duplicate content on a website. The problem I have is that the strcat functions don't seem to be doing anything. I'm trying to use them to prepend "http://example.com" to the resulting URL for a user to redirect to if it initially contained groups of 2 or more slashes stuck together.
static int handler(request_rec *r){
if (strcmp(r->handler,"httpd/unix-directory")==0){return DECLINED;}
unsigned long flag=0,ct=0;
char xi[100004],*xuri=xi,*up=r->unparsed_uri;
*xuri='\0';
strcat(xuri,"http://");
strcat(xuri,r->hostname);
while (*up != '\0'){
if (*up=='/'){flag++;}else{flag=0;}
if (flag < 2){*xuri=*up;xuri++;ct++;if (ct >= 100000){break;}}
if (flag > 1){flag=2;}
up++;
}
if (ct < 100000){
if (ct > 0){xuri--;}
if (*xuri=='/'){*xuri='\0';}
xuri++;*xuri='\0';
xuri=xi;up=r->unparsed_uri;
if (strcmp(up,xuri)==0){return DECLINED;} //no redirect for same URL
r->content_type = "text/html";
apr_table_set(r->headers_out,"Location",xuri);
return HTTP_MOVED_PERMANENTLY;
}else{
return HTTP_INTERNAL_SERVER_ERROR;
}
}
Currently the tail of any URL (for example, the /123 part from http://example.com/123) is read and only the tail is outputted, but I want the http://example.com/ part prepended.
What can I do to get strcat to work in my favor?
strcat doesn't update xuri. So xuri is still pointing to the beginning of the string after the two calls to strcat. So when the code reaches the statements *xuri=*up;xuri++;, it's overwriting the string starting from the beginning.
You can fix the problem by using sprintf instead, since that allows you to update xuri appropriately, e.g. replace these three lines
*xuri='\0';
strcat(xuri,"http://");
strcat(xuri,r->hostname);
with this line
xuri += sprintf( "http://%s", r->hostname );

a stack overflow (about "evhttp_uri_parse")

code realize function that reading file(contain lots of urls) ,every url pass through "evhttp_uri_parse" getting host and path.But it has a error that evhttp_uri_parse parse fail ,return NULL。Possibly reason is a stack overflow.
FILE *fp=fopen(argv[1],"rb");
if(NULL==fp)
{
printf("open url_file is error %d::%s\n",errno,strerror(errno));
return 0;
}
char url_buf[2048];
memset(url_buf,'\0',sizeof(url_buf));
fgets(url_buf,sizeof(url_buf),fp);
while(!feof(fp))
{
if(strlen(url_buf)>1)
{
printf("url_buf::%s",url_buf);
#if 1
struct evhttp_uri *ev_uri=NULL;
ev_uri=evhttp_uri_parse(url_buf);
if(ev_uri==NULL)
{
printf("parse uri error::%d,%s\n",errno,strerror(errno));
}
const char *host=evhttp_uri_get_host(ev_uri);
const char *path=evhttp_uri_get_path(ev_uri);
printf("query host::%s,path::%s\n",host,path);
evhttp_uri_free(ev_uri);
#endif
}
memset(url_buf,'\0',sizeof(url_buf));
fgets(url_buf,sizeof(url_buf),fp);
}
fclose(fp);
fgets(url_buf,sizeof(url_buf)+1,fp) should be changed to fgets(url_buf,sizeof(url_buf),fp)
fgets adds '\n' at the end of the string. Try to remove it and see if it helps.
if your url for any reason greater than 2048 character size then fgets will not completely return you the url you wanted and return you a part of it (with 2047 character) with a null character at 2048'th location only.
so thats why it's a bad idea to put sizeof(url_buf)+1. it will lead to undefined behavior since you will be accessing a location which is out of bound to url_buf array.
so check whether you got a string with newline character and change it to a null character, if you didn't get a newline character in the string then you might want to read until you get a newline to get the complete url.
this is applicable only if your url's are delimited by newline.

Bus Error on void function return

I'm learning to use libcurl in C. To start, I'm using a randomized list of accession names to search for protein sequence files that may be found hosted here. These follow a set format where the first line is a variable length (but which contains no information I'm trying to query) then a series of capitalized letters with a new line every sixty (60) characters (what I want to pull down, but reformat to eighty (80) characters per line).
I have the call itself in a single function:
//finds and saves the fastas for each protein (assuming on exists)
void pullFasta (proteinEntry *entry, char matchType, FILE *outFile) {
//Local variables
URL_FILE *handle;
char buffer[2] = "", url[32] = "http://www.uniprot.org/uniprot/", sequence[2] = "";
//Build full URL
/*printf ("u:%s\nt:%s\n", url, entry->title); /*This line was used for debugging.*/
strcat (url, entry->title);
strcat (url, ".fasta");
//Open URL
/*printf ("u:%s\n", url); /*This line was used for debugging.*/
handle = url_fopen (url, "r");
//If there is data there
if (handle != NULL) {
//Skip the first line as it's got useless info
do {
url_fread(buffer, 1, 1, handle);
} while (buffer[0] != '\n');
//Grab the fasta data, skipping newline characters
while (!url_feof (handle)) {
url_fread(buffer, 1, 1, handle);
if (buffer[0] != '\n') {
strcat (sequence, buffer);
}
}
//Print it
printFastaEntry (entry->title, sequence, matchType, outFile);
}
url_fclose (handle);
return;
}
With proteinEntry being defined as:
//Entry for fasta formatable data
typedef struct proteinEntry {
char title[7];
struct proteinEntry *next;
} proteinEntry;
And the url_fopen, url_fclose, url_feof, url_read, and URL_FILE code found here, they mimic the file functions for which they are named.
As you can see I've been doing some debugging with the URL generator (uniprot URLs follow the same format for different proteins), I got it working properly and can pull down the data from the site and save it to file in the proper format that I want. I set the read buffer to 1 because I wanted to get a program that was very simplistic but functional (if inelegant) before I start playing with things, so I would have a base to return to as I learned.
I've tested the url_<function> calls and they are giving no errors. So I added incremental printf calls after each line to identify exactly where the bus error is occurring and it is happening at return;.
My understanding of bus errors is that it's a memory access issue wherein I'm trying to get at memory that my program doesn't have control over. My confusion comes from the fact that this is happening at the return of a void function. There's nothing being read, written, or passed to trigger the memory error (as far as I understand it, at least).
Can anyone point me in the right direction to fix my mistake please?
EDIT: As #BLUEPIXY pointed out I had a potential url_fclose (NULL). As #deltheil pointed out I had sequence as a static array. This also made me notice I'm repeating my bad memory allocation for url, so I updated it and it now works. Thanks for your help!
If we look at e.g http://www.uniprot.org/uniprot/Q6GZX1.fasta and skip the first line (as you do) we have:
MNAKYDTDQGVGRMLFLGTIGLAVVVGGLMAYGYYYDGKTPSSGTSFHTASPSFSSRYRY
Which is a 60 characters string.
When you try to read this sequence with:
//Grab the fasta data, skipping newline characters
while (!url_feof (handle)) {
url_fread(buffer, 1, 1, handle);
if (buffer[0] != '\n') {
strcat (sequence, buffer);
}
}
The problem is sequence is not expandable and not large enough (it is a fixed length array of size 2).
So make sure to choose a large enough size to hold any sequence, or implement the ability to expand it on-the-fly.

Splitting a comma-delimited string of integers

My background is not in C (it's in Real Studio - similar to VB) and I'm really struggling to split a comma-delimited string since I'm not used to low-level string handling.
I'm sending strings to an Arduino over serial. These strings are commands in a certain format. For instance:
#20,2000,5!
#10,423,0!
'#' is the header indicating a new command and '!' is the terminating footer marking the end of a command. The first integer after '#' is the command id and the remaining integers are data (the number of integers passed as data may be anywhere from 0 - 10 integers).
I've written a sketch that gets the command (stripped of the '#' and '!') and calls a function called handleCommand() when there is a command to handle. The problem is, I really don't know how to split this command up to handle it!
Here's the sketch code:
String command; // a string to hold the incoming command
boolean commandReceived = false; // whether the command has been received in full
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// main loop
handleCommand();
}
void serialEvent(){
while (Serial.available()) {
// all we do is construct the incoming command to be handled in the main loop
// get the incoming byte from the serial stream
char incomingByte = (char)Serial.read();
if (incomingByte == '!')
{
// marks the end of a command
commandReceived = true;
return;
}
else if (incomingByte == '#')
{
// marks the start of a new command
command = "";
commandReceived = false;
return;
}
else
{
command += incomingByte;
return;
}
}
}
void handleCommand() {
if (!commandReceived) return; // no command to handle
// variables to hold the command id and the command data
int id;
int data[9];
// NOT SURE WHAT TO DO HERE!!
// flag that we've handled the command
commandReceived = false;
}
Say my PC sends the Arduino the string "#20,2000,5!". My sketch ends up with a String variable (called command) that contains "20,2000,5" and the commandRecieved boolean variable is set to True so the handleCommand() function is called.
What I would like to do in the (currently useless) handleCommand() function is assign 20 to a variable called id and 2000 and 5 to an array of integers called data, i.e: data[0] = 2000, data[1] = 5, etc.
I've read about strtok() and atoi() but frankly I just can't get my head around them and the concept of pointers. I'm sure my Arduino sketch could be optimised too.
Since you're using the Arduino core String type, strtok and other string.h functions aren't appropriate. Note that you can change your code to use standard C null-terminated strings instead, but using Arduino String will let you do this without using pointers.
The String type gives you indexOf and substring.
Assuming a String with the # and ! stripped off, finding your command and arguments would look something like this:
// given: String command
int data[MAX_ARGS];
int numArgs = 0;
int beginIdx = 0;
int idx = command.indexOf(",");
String arg;
char charBuffer[16];
while (idx != -1)
{
arg = command.substring(beginIdx, idx);
arg.toCharArray(charBuffer, 16);
// add error handling for atoi:
data[numArgs++] = atoi(charBuffer);
beginIdx = idx + 1;
idx = command.indexOf(",", beginIdx);
}
data[numArgs++] = command.substring(beginIdx);
This will give you your entire command in the data array, including the command number at data[0], while you've specified that only the args should be in data. But the necessary changes are minor.
seems to work, could be buggy:
#include<stdio.h>
#include <string.h>
int main(){
char string[]="20,2000,5";
int a,b,c;
sscanf(string,"%i,%i,%i",&a,&b,&c);
printf("%i %i %i\n",a,b,c);
a=b=c=0;
a=atoi(strtok(string,","));
b=atoi(strtok(0,","));
c=atoi(strtok(0,","));
printf("%i %i %i\n",a,b,c);
return 0;
}

Resources