array packetizer in JSON format in C - arrays

I am developing the JSON array packetizer in C to send response back to http server
example format in JSON array
"fat": [
23,
152689,
"Segmentation Fault"
]
Code in C
void arrFunc(char* buffer, const char* name, const int* value, int count)
{
if ((buffer == NULL) || (name == NULL))
{
return;
}
char numberChar[VALUE_FIELD_LENGTH];
strncat(buffer, "\"", 1);
strncat(buffer, name, strlen(name));
strncat(buffer, "\":", 2);
strncat(buffer, "[", 1);
if (value != NULL)
{
for (int i = 0; i < count; i++)
- {
snprintf(numberChar, VALUE_FIELD_LENGTH, "%u", value[i]);
strncat(buffer, numberChar, 1);
if(i<count-1)
strncat(buffer, ",", 1);
numberChar[i] = '\0';
}
}
strncat(buffer, "]", 1);
}
/* main *//
int arr[5] = { 1,2,3,4,5 };
char* msg;
if (msg != NULL)
{
msg[0] = '\0';
arrFunc(msg, "fat",(const int *) arr,3);
}
Output :
"fat": [
1,
2,
3
]
I am able to achieve array packetizer of similar data types like integer but how to achive for
different data type [23,152689,"Segmentation Fault"]

There's many ways to solve this problem, but one of them is tagged unions.
#include <stdio.h>
// TODO: include an implementation of a map
struct map {};
// TODO: include a dynamic array that knows size of data it holds
struct array {};
enum DataType {
JSON_MAP,
JSON_ARRAY,
JSON_NUMBER,
JSON_STRING
};
union Data {
float number;
char* string;
struct map map;
struct array array;
};
struct Json {
enum DataType kind;
union Data data;
};
// TODO: turn this into json serializer
void print_json(struct Json data) {
switch(data.kind) {
case JSON_NUMBER:
printf("%d\n", data.data.number);
break;
case JSON_STRING:
puts(data.data.string);
break;
default:
puts("TODO: print map and array");
}
}
int main() {
struct Json data1 = { .kind = JSON_NUMBER, .data.number = 12.34 };
struct Json data2 = { .kind = JSON_STRING, .data.string = "Hello, Json!" };
// invalid, but we never read it in this example
struct Json data3 = { .kind = JSON_ARRAY };
print_json(data1);
print_json(data2);
print_json(data3);
}
I don't think this requires further explanation but keep in mind that both the map and array should hold elements of type struct Json too, which is how you can build structures such as:
{ // JSON_MAP
"example": [ // JSON_ARRAY
1, // JSON_NUMBER
"42", // JSON_STRING
{ "etc": { "1": 2, "a": [3, 2, 1] } } // JSON_MAP (again)
]
}

Related

How to assign a character to a string pointed by a struct?

I have a struct that contains a field named void * user_data.
Here is the library declaration:
typedef struct esp_http_client_event {
esp_http_client_event_id_t event_id;
esp_http_client_handle_t client;
void *data;
int data_len;
void *user_data;
char *header_key;
char *header_value;
} esp_http_client_event_t;
When I declare the struct, I assign a buffer to user_data:
char g_http_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = { 0 };
...
esp_http_client_config_t config = {
.url = WEB_URL,
.event_handler = client_event_handler,
.transport_type = HTTP_TRANSPORT_OVER_SSL,
.crt_bundle_attach = esp_crt_bundle_attach,
.buffer_size_tx = 1024,
.user_data = g_http_response_buffer,
};
After that, I want to manipulate g_http_response_buffer by using the structure, passed to a function (the function is a callback, but I don't think it's relevant).
Inside the function, I use it in the following way:
esp_err_t
client_event_handler (esp_http_client_event_handle_t evt)
{
static int output_len = 0;
esp_err_t ret = ESP_OK;
switch (evt->event_id)
{
case HTTP_EVENT_ERROR:
ESP_LOGI(g_p_tag, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(g_p_tag, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGI(g_p_tag, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGI(g_p_tag, "HTTP_EVENT_ON_HEADER, key=%s, value=%s",
evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGI(g_p_tag, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
if (!esp_http_client_is_chunked_response(evt->client))
{
if (evt->user_data)
{
memcpy(evt->user_data + output_len, evt->data,
evt->data_len);
ESP_LOGI(g_p_tag, "Dati non chunk: %s",
(char *) evt->user_data);
}
if (ESP_OK == ret)
{
output_len += evt->data_len;
}
}
else
{
if (evt->user_data)
{
memcpy(evt->user_data + output_len, evt->data,
evt->data_len);
ESP_LOGI(g_p_tag, "Dati chunk: %s",
(char *) evt->user_data);
}
if (ESP_OK == ret)
{
output_len += evt->data_len;
}
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGI(g_p_tag, "HTTP_EVENT_ON_FINISH");
g_http_response_buffer[output_len] = '\0'; // <- HERE!
ESP_LOGI(g_p_tag, "Dato finale: %s", (char *) evt->user_data);
output_len = 0;
break;
}
return ret;
} /* client_event_handler() */
How can I insert the terminator string by using a pointer to user_data?
I tried (evt + output_len)->user_data = '\0' but it seems wrong.
How can I insert the terminator string by using a pointer to user_data?
You cannot "insert" into arrays strictly speaking. You can assign a char in any index to be a null terminator like this:
char* ptr_to_user_data = config.user_data;
assert(index < MAX_HTTP_OUTPUT_BUFFER);
ptr_to_user_data[index] = '\0';

C: Loop through struct and concat to string

I have C program with the following struct:
struct {
char *ext;
char *filetype;
} extensions [] = {
{"gif", "image/gif" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{0,0}
};
How do I create a function that returns a string that contains only the extensions separated by new lines? Basically this is what to be able to do this:
printf("\nThe following extensions are supported:\n%s",GetExtensions());
And have it output this:
The following extensions are supported:
.gif
.jpg
.jpeg
.png
I think I've got the looping part correct, but I'm not understanding how to concat each ext + \n to a string:
#include <leaving these off for brevity...>
struct {
char *ext;
char *filetype;
} extensions [] = {
{"gif", "image/gif" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{0,0}
};
char *getExtensions(void) {
char* exts;
int i;
for(i=0;extensions[i].ext != 0;i++){
// What do I do here??
}
return exts;
}
int main(int argc, char **argv){
printf("\nThe following extensions are supported: \n%s",GetExtensions());
}
It seems you mean the following.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct extension
{
char *ext;
char *filetype;
};
char * getExtensions( const struct extension a[] )
{
size_t n = 0;
for ( size_t i = 0; a[i].ext != NULL; i++ )
{
n += strlen( a[i].ext ) + 1;
}
char *s = malloc( n + 1 );
if ( s != NULL )
{
s[0] = '\0';
for ( size_t i = 0; a[i].ext != NULL; i++ )
{
strcat( s, a[i].ext );
strcat( s, "\n" );
}
}
return s;
}
int main(void)
{
struct extension extensions [] =
{
{"gif", "image/gif" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{ NULL, NULL }
};
char *s = getExtensions( extensions );
printf( "The following extensions are supported:\n%s", s );
free( s );
return 0;
}
The program output is
The following extensions are supported:
gif
jpg
jpeg
png
#include <stdio.h>
#include <string.h>
// Your struct
struct extensionInfo {
char *ext;
char *filetype;
};
struct extensionInfo extensions [] = {
{"gif", "image/gif" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{0,0}
};
int main(int argc, char **args, char **env) {
char buffer[1024];
struct extensionInfo *ext;
// Initialize the buffer
memset(buffer, 0, sizeof(buffer));
// Insert your first text.
strncat(buffer, "The following extensions are supported:", sizeof(buffer) - 1);
// Loop through your array and append everything
for (ext = extensions; ext->ext != 0; ext++) {
strncat(buffer, "\n", sizeof(buffer) - 1);
strncat(buffer, ext->ext, sizeof(buffer) - 1);
}
// Show your result
printf("%s\n", buffer);
return 0;
}
Here is a commented example which works. If you have any questions, feel free to ask.
I think the following is what you wish. You can read the comments to grasp how it works.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct {
char *ext;
char *filetype;
} extensions [] = {
{"gif", "image/gif" },
{"jpg", "image/jpg" },
{"jpeg","image/jpeg"},
{"png", "image/png" },
{0,0}
};
char *getExtensions(void) {
size_t count = 0;
// let's know how many characters are needed for all extensions
for(int i = 0; extensions[i].ext != 0; ++i) {
size_t j = 0;
for (; extensions[i].ext[j] != 0; ++j) ;
count += j + 1; // +1 for every newline
}
// +1 for null terminator
char *str = calloc(count + 1, sizeof(char));
// let's concatenate
for(size_t i = 0; extensions[i].ext != 0; ++i) {
strcat(str, extensions[i].ext);
strcat(str, "\n");
}
return str;
}
int main(int argc, char **argv){
char * const result = getExtensions();
printf("\nThe following extensions are supported: \n%s", result);
free(result);
}

mapping structures in struct C

im trying to index number of struct under one struct.
im tying to pass the data in the first struct to the struct pointer but i get return null.
my code is :
struct complex{
char * rNum; /* real number */
char *iNum; /* imaginary number*/
};
struct complex A = {"0","0"};
struct complex B = {"0","0"};
struct complex C = {"0","0"};
struct complex D = {"0","0"};
struct complex E = {"0","0"};
struct complex F = {"0","0"};
struct mapping{
char *key;
struct complex *P;
} complex_map [] = {
{ "A", &A },
{ "B", &B },
{ "C", &C },
{ "D", &D },
{ "E", &E },
{ "F", &F },
};
char call_complex(const char *name) {
int i;
for (i = 0; i < (sizeof(complex_map) / sizeof(complex_map[0])); i++) {
if (!strcmp(complex_map[i].key, name) && complex_map[i].P->rNum) {
complex_map[i].P->rNum;
return 0;
}
}
printf("Invalid\n");
}
and my call function is :
void read_comp(char *str){
printf(" %s",call_complex(str));
}
when i run this code i get return (null)
why?
thanks for helping
Try This:
#include <stdio.h>
struct complex{
char * rNum; /* real number */
char *iNum; /* imaginary number*/
};
struct complex A = {"1","0"};
struct complex B = {"2","0"};
struct complex C = {"3","0"};
struct complex D = {"4","0"};
struct complex E = {"5","0"};
struct complex F = {"6","0"};
struct mapping{
char *key;
struct complex *P;
} complex_map [] = {
{ "A", &A },
{ "B", &B },
{ "C", &C },
{ "D", &D },
{ "E", &E },
{ "F", &F },
};
char call_complex(const char *name)
{
int i;
for (i = 0; i < (sizeof(complex_map) / sizeof(complex_map[0])); i++)
{
if (!strcmp(complex_map[i].key, name) && complex_map[i].P->rNum)
{
return *(complex_map[i].P->rNum); // Correction
}
}
printf("Invalid\n");
}
int main()
{
printf("Got: %c \n",call_complex("A")); // Just example
return 0;
}
Thanks.

Accessing certain elements in an Struct in C

So I have the following struct I created:
struct _I_TypeInstructions {
const char *instructionName;
char *opcode;
} I_TypeInstructions[] = { { "lw", "100011" }, { "sw", "101011" }, { "beq",
"000100" } };
typedef struct _I_TypeInstructions I_TypeInstructionsStruct;
If I have a new instructionName and I want to check if it is in the I_TypeInstructionsStruct how do I iterate through just the *instructionName part of the struct above. For example the function I want to write would look something like
bool checkIfInstructionIsI_Type(char *instructionName) {
// somehow iterate through instructionNames in the struct above
// checking if parameter char *instructionName in this method is equal to
// "lw" "sw" "beq" but skipping over the binary numbers.
}
Searching a list of structs is rather straight forward:
bool checkIfInstructionIsI_Type(char *instructionName)
{
for (int i = 0; i<NumInstructions; i++)
{
if (strcmp(I_TypeInstructions[i].instructionName, instructionName) == 0)
{
return true;
}
}
return false;
}
int i;
for(i = 0; i < 3; ++i)
{
if (strcmp(instructions[i].instructionName, instructionName) == 0)
{
printf("Match found");
}
}
It's generally more useful to return the actual element that matches your string. It's the same amount of work anyway.
Add an empty element to the end of your array and then you have a end marker.
typedef struct _I_TypeInstructions {
const char *instructionName;
char *opcode;
} I_TypeInstructionsStruct;
I_TypeInstructionsStruct I_TypeInstructions[] = {
{ "lw", "100011" },
{ "sw", "101011" },
{ "beq", "000100" },
{ 0, 0}
};
I_TypeInstructionsStruct *find_instruction(char *name)
{
I_TypeInstructionsStruct *i ;
for (i = I_TypeInstructions ; i->instructionName ; i++)
if (!strcmp(i->instructionName,name)) return i ;
return 0 ;
}

changing size of array

I have the following code:
typedef struct my_data {
char* name;
}my_data;
my_data data[]={
{ .name = "Peter" },
{ .name = "James" },
{ .name = "John" },
{ .name = "Mike" }
};
void loaddata()
{
FILE * in;
if((in = fopen("data.txt","rt")) != NULL) {
memset(data, 0, sizeof(data));
int i = 0;
while(!feof(in))
{
fscanf(in,"%s", &data[i].name);
i++;
};
fclose(in);
}
}
to read contents and process them I use this:
for (i=0; i<sizeof(data)/sizeof(data[0]); i++)
but if the number of lines in file is less than the number of defined array I get a lot of empty records so I modified it into:
for (i=0; (i<sizeof(data)/sizeof(data[0])) && strlen(data[i].name)>0; i++)
which is working fine but I'm sure I will get errors if the number of lines in file will be larger than the defined array size.
Any idea how to make this code safe? To change array dynamically?
EDIT:
this way is working with size 300
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef struct my_data {
char name[100];
}my_data;
struct my_data data[300];
my_data data_arr[]={
{ .name = "Peter" },
{ .name = "James" },
{ .name = "John" },
{ .name = "Mike" }
};
void process_data()
{
char name[100];
int i;
for (i=0; (i<sizeof(data)/sizeof(data[0])) && strlen(data[i].name)>0; i++) {
sprintf(name, "%s", data[i].name);
printf("%s\n", name);
}
}
void load_data()
{
int i = 0;
FILE * in;
if((in = fopen("data.txt","rt")) != NULL) {
while(!feof(in))
{
fscanf(in,"%s", &data[i].name);
i++;
};
fclose(in);
}
else
{
for (i=0; (i<sizeof(data_arr)/sizeof(data_arr[0])) && strlen(data_arr[i].name)>0; i++) {
sprintf(data[i].name, "%s", data_arr[i].name);
}
}
return;
}
int main()
{
load_data();
process_data();
return 0;
}
Arrays do not grow dynamically in C. So you have a few approaches:
get a pointer to a block of memory (using malloc) and use realloc whenever you need more space for an array - and index into your pointer
create a linked list using malloc for every new item you want to add to your list
Don't forget when using malloc to call free on every single block that you called malloc for.

Resources