mirror of
https://github.com/swaywm/sway.git
synced 2026-04-21 06:46:22 -04:00
Merge 3e69928f13 into c32a507303
This commit is contained in:
commit
df9b88befb
7 changed files with 131 additions and 86 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -94,9 +95,15 @@ struct ipc_response *ipc_recv_response(int socketfd) {
|
|||
goto error_1;
|
||||
}
|
||||
|
||||
memcpy(&response->size, data + sizeof(ipc_magic), sizeof(uint32_t));
|
||||
uint32_t size;
|
||||
memcpy(&size, data + sizeof(ipc_magic), sizeof(uint32_t));
|
||||
response->size = size;
|
||||
memcpy(&response->type, data + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t));
|
||||
|
||||
if (response->size >= SSIZE_MAX) {
|
||||
sway_abort("Unable to receive overly long IPC response");
|
||||
}
|
||||
|
||||
char *payload = malloc(response->size + 1);
|
||||
if (!payload) {
|
||||
goto error_2;
|
||||
|
|
@ -126,11 +133,16 @@ void free_ipc_response(struct ipc_response *response) {
|
|||
free(response);
|
||||
}
|
||||
|
||||
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) {
|
||||
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, size_t *len) {
|
||||
char data[IPC_HEADER_SIZE];
|
||||
|
||||
if (*len > UINT32_MAX) {
|
||||
sway_abort("Unable to send overly long IPC payload");
|
||||
}
|
||||
uint32_t size = *len;
|
||||
memcpy(data, ipc_magic, sizeof(ipc_magic));
|
||||
memcpy(data + sizeof(ipc_magic), len, sizeof(*len));
|
||||
memcpy(data + sizeof(ipc_magic) + sizeof(*len), &type, sizeof(type));
|
||||
memcpy(data + sizeof(ipc_magic), &size, sizeof(size));
|
||||
memcpy(data + sizeof(ipc_magic) + sizeof(size), &type, sizeof(type));
|
||||
|
||||
if (write(socketfd, data, IPC_HEADER_SIZE) == -1) {
|
||||
sway_abort("Unable to send IPC header");
|
||||
|
|
@ -141,9 +153,15 @@ char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint3
|
|||
}
|
||||
|
||||
struct ipc_response *resp = ipc_recv_response(socketfd);
|
||||
char *response = resp->payload;
|
||||
*len = resp->size;
|
||||
free(resp);
|
||||
char *response;
|
||||
if (resp == NULL) {
|
||||
response = NULL;
|
||||
*len = 0;
|
||||
} else {
|
||||
response = resp->payload;
|
||||
*len = resp->size;
|
||||
free(resp);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* encoded payload string.
|
||||
*/
|
||||
struct ipc_response {
|
||||
uint32_t size;
|
||||
size_t size;
|
||||
uint32_t type;
|
||||
char *payload;
|
||||
};
|
||||
|
|
@ -32,7 +32,7 @@ int ipc_open_socket(const char *socket_path);
|
|||
* Issues a single IPC command and returns the buffer. len will be updated with
|
||||
* the length of the buffer returned from sway.
|
||||
*/
|
||||
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len);
|
||||
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, size_t *len);
|
||||
/**
|
||||
* Receives a single IPC response and returns an ipc_response.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#define event_mask(ev) (1 << (ev & 0x7F))
|
||||
|
||||
// maximum size of payload is 4 MB
|
||||
#define IPC_MAX_SIZE 4e6
|
||||
|
||||
enum ipc_command_type {
|
||||
// i3 command types - see i3's I3_REPLY_TYPE constants
|
||||
IPC_COMMAND = 0,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ struct ipc_client {
|
|||
struct sway_server *server;
|
||||
int fd;
|
||||
enum ipc_command_type subscribed_events;
|
||||
size_t read_buffer_len;
|
||||
size_t read_buffer_size;
|
||||
char *read_buffer;
|
||||
size_t write_buffer_len;
|
||||
size_t write_buffer_size;
|
||||
char *write_buffer;
|
||||
|
|
@ -186,11 +189,23 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
|||
client_fd, WL_EVENT_READABLE, ipc_client_handle_readable, client);
|
||||
client->writable_event_source = NULL;
|
||||
|
||||
client->read_buffer_size = 128;
|
||||
client->read_buffer_len = 0;
|
||||
client->read_buffer = malloc(client->read_buffer_size);
|
||||
if (!client->read_buffer) {
|
||||
sway_log(SWAY_ERROR, "Unable to allocate ipc client read buffer");
|
||||
free(client);
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
client->write_buffer_size = 128;
|
||||
client->write_buffer_len = 0;
|
||||
client->write_buffer = malloc(client->write_buffer_size);
|
||||
if (!client->write_buffer) {
|
||||
sway_log(SWAY_ERROR, "Unable to allocate ipc client write buffer");
|
||||
free(client->read_buffer);
|
||||
free(client);
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -220,49 +235,67 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
|
|||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
if ((size_t)read_available + 1 > SIZE_MAX - client->read_buffer_len) {
|
||||
sway_log_errno(SWAY_INFO, "Receiving too much data from IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Wait for the rest of the command payload in case the header has already been read
|
||||
if (client->pending_length > 0) {
|
||||
if ((uint32_t)read_available >= client->pending_length) {
|
||||
// Reset pending values.
|
||||
uint32_t pending_length = client->pending_length;
|
||||
enum ipc_command_type pending_type = client->pending_type;
|
||||
client->pending_length = 0;
|
||||
ipc_client_handle_command(client, pending_length, pending_type);
|
||||
if (client->read_buffer_len + read_available >= client->read_buffer_size) {
|
||||
size_t new_size = client->read_buffer_len + read_available + 1;
|
||||
char *new_buffer = realloc(client->read_buffer, new_size);
|
||||
if (new_buffer == NULL) {
|
||||
sway_log_errno(SWAY_INFO, "Unable to increase read buffer for IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
client->read_buffer = new_buffer;
|
||||
client->read_buffer_size = new_size;
|
||||
}
|
||||
|
||||
if (read_available < (int) IPC_HEADER_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t buf[IPC_HEADER_SIZE];
|
||||
// Should be fully available, because read_available >= IPC_HEADER_SIZE
|
||||
ssize_t received = recv(client_fd, buf, IPC_HEADER_SIZE, 0);
|
||||
ssize_t received = recv(client_fd, client->read_buffer + client->read_buffer_len, read_available, 0);
|
||||
if (received == -1) {
|
||||
sway_log_errno(SWAY_INFO, "Unable to receive header from IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
client->read_buffer_len += received;
|
||||
|
||||
if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
|
||||
sway_log(SWAY_DEBUG, "IPC header check failed");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
if (client->pending_length == 0) {
|
||||
if (client->read_buffer_len < (size_t) IPC_HEADER_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp(client->read_buffer, ipc_magic, sizeof(ipc_magic)) != 0) {
|
||||
sway_log(SWAY_DEBUG, "IPC header check failed");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(&client->pending_length,
|
||||
client->read_buffer + sizeof(ipc_magic), sizeof(uint32_t));
|
||||
memcpy(&client->pending_type,
|
||||
client->read_buffer + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t));
|
||||
if (client->pending_length > IPC_MAX_SIZE) {
|
||||
sway_log_errno(SWAY_INFO, "Receiving too much payload from IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&client->pending_length, buf + sizeof(ipc_magic), sizeof(uint32_t));
|
||||
memcpy(&client->pending_type, buf + sizeof(ipc_magic) + sizeof(uint32_t), sizeof(uint32_t));
|
||||
|
||||
if (read_available - received >= (long)client->pending_length) {
|
||||
// Reset pending values.
|
||||
if (client->read_buffer_len >= IPC_HEADER_SIZE + client->pending_length) {
|
||||
uint32_t pending_length = client->pending_length;
|
||||
enum ipc_command_type pending_type = client->pending_type;
|
||||
client->pending_length = 0;
|
||||
char c = client->read_buffer[IPC_HEADER_SIZE + client->pending_length];
|
||||
client->read_buffer[IPC_HEADER_SIZE + client->pending_length] = '\0';
|
||||
ipc_client_handle_command(client, pending_length, pending_type);
|
||||
// Reset values.
|
||||
client->read_buffer[IPC_HEADER_SIZE + client->pending_length] = c;
|
||||
memmove(client->read_buffer, client->read_buffer + IPC_HEADER_SIZE + client->pending_length,
|
||||
client->read_buffer_len - IPC_HEADER_SIZE - client->pending_length);
|
||||
client->read_buffer_len -= IPC_HEADER_SIZE + client->pending_length;
|
||||
client->pending_length = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -565,6 +598,7 @@ void ipc_client_disconnect(struct ipc_client *client) {
|
|||
i++;
|
||||
}
|
||||
list_del(ipc_client_list, i);
|
||||
free(client->read_buffer);
|
||||
free(client->write_buffer);
|
||||
close(client->fd);
|
||||
free(client);
|
||||
|
|
@ -603,24 +637,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
return;
|
||||
}
|
||||
|
||||
char *buf = malloc(payload_length + 1);
|
||||
if (!buf) {
|
||||
sway_log_errno(SWAY_INFO, "Unable to allocate IPC payload");
|
||||
ipc_client_disconnect(client);
|
||||
return;
|
||||
}
|
||||
if (payload_length > 0) {
|
||||
// Payload should be fully available
|
||||
ssize_t received = recv(client->fd, buf, payload_length, 0);
|
||||
if (received == -1)
|
||||
{
|
||||
sway_log_errno(SWAY_INFO, "Unable to receive payload from IPC client");
|
||||
ipc_client_disconnect(client);
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
buf[payload_length] = '\0';
|
||||
char *buf = client->read_buffer + IPC_HEADER_SIZE;
|
||||
|
||||
switch (payload_type) {
|
||||
case IPC_COMMAND:
|
||||
|
|
@ -647,14 +664,14 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
list_del(res_list, 0);
|
||||
}
|
||||
list_free(res_list);
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_SEND_TICK:
|
||||
{
|
||||
ipc_event_tick(buf);
|
||||
ipc_send_reply(client, payload_type, "{\"success\": true}", 17);
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_OUTPUTS:
|
||||
|
|
@ -695,7 +712,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(outputs); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_WORKSPACES:
|
||||
|
|
@ -706,7 +723,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(workspaces); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_SUBSCRIBE:
|
||||
|
|
@ -717,7 +734,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
const char msg[] = "{\"success\": false}";
|
||||
ipc_send_reply(client, payload_type, msg, strlen(msg));
|
||||
sway_log(SWAY_INFO, "Failed to parse subscribe request");
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
bool is_tick = false;
|
||||
|
|
@ -748,7 +765,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, msg, strlen(msg));
|
||||
json_object_put(request);
|
||||
sway_log(SWAY_INFO, "Unsupported event type in subscribe request");
|
||||
goto exit_cleanup;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -760,7 +777,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, IPC_EVENT_TICK, tickmsg,
|
||||
strlen(tickmsg));
|
||||
}
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_INPUTS:
|
||||
|
|
@ -774,7 +791,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(inputs); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_SEATS:
|
||||
|
|
@ -788,7 +805,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(seats); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_TREE:
|
||||
|
|
@ -798,7 +815,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(tree);
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_MARKS:
|
||||
|
|
@ -809,7 +826,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(marks);
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_VERSION:
|
||||
|
|
@ -819,7 +836,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(version); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_BAR_CONFIG:
|
||||
|
|
@ -849,7 +866,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
const char *error = "{ \"success\": false, \"error\": \"No bar with that ID\" }";
|
||||
ipc_send_reply(client, payload_type, error,
|
||||
(uint32_t)strlen(error));
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
json_object *json = ipc_json_describe_bar_config(bar);
|
||||
const char *json_string = json_object_to_json_string(json);
|
||||
|
|
@ -857,7 +874,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
(uint32_t)strlen(json_string));
|
||||
json_object_put(json); // free
|
||||
}
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_BINDING_MODES:
|
||||
|
|
@ -871,7 +888,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(modes); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_BINDING_STATE:
|
||||
|
|
@ -881,7 +898,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(current_mode); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_GET_CONFIG:
|
||||
|
|
@ -892,7 +909,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
ipc_send_reply(client, payload_type, json_string,
|
||||
(uint32_t)strlen(json_string));
|
||||
json_object_put(json); // free
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPC_SYNC:
|
||||
|
|
@ -900,17 +917,13 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
|||
// It was decided sway will not support this, just return success:false
|
||||
const char msg[] = "{\"success\": false}";
|
||||
ipc_send_reply(client, payload_type, msg, strlen(msg));
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
sway_log(SWAY_INFO, "Unknown IPC command type %x", payload_type);
|
||||
goto exit_cleanup;
|
||||
break;
|
||||
}
|
||||
|
||||
exit_cleanup:
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_type,
|
||||
|
|
@ -928,7 +941,7 @@ bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_typ
|
|||
client->write_buffer_size *= 2;
|
||||
}
|
||||
|
||||
if (client->write_buffer_size > 4e6) { // 4 MB
|
||||
if (client->write_buffer_size > IPC_MAX_SIZE) {
|
||||
sway_log(SWAY_ERROR, "Client write buffer too big (%zu), disconnecting client",
|
||||
client->write_buffer_size);
|
||||
ipc_client_disconnect(client);
|
||||
|
|
|
|||
|
|
@ -89,9 +89,9 @@ void detect_proprietary(int allow_unsupported_gpu) {
|
|||
|
||||
void run_as_ipc_client(char *command, char *socket_path) {
|
||||
int socketfd = ipc_open_socket(socket_path);
|
||||
uint32_t len = strlen(command);
|
||||
size_t len = strlen(command);
|
||||
char *resp = ipc_single_command(socketfd, IPC_COMMAND, command, &len);
|
||||
printf("%s\n", resp);
|
||||
printf("%s\n", resp == NULL ? "(null)" : resp);
|
||||
free(resp);
|
||||
close(socketfd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include "util.h"
|
||||
|
||||
void ipc_send_workspace_command(struct swaybar *bar, const char *ws) {
|
||||
uint32_t size = strlen("workspace \"\"") + strlen(ws);
|
||||
size_t size = strlen("workspace \"\"") + strlen(ws);
|
||||
for (size_t i = 0; i < strlen(ws); ++i) {
|
||||
if (ws[i] == '"' || ws[i] == '\\') {
|
||||
++size;
|
||||
|
|
@ -343,9 +343,12 @@ bool ipc_get_workspaces(struct swaybar *bar) {
|
|||
free_workspaces(&output->workspaces);
|
||||
output->focused = false;
|
||||
}
|
||||
uint32_t len = 0;
|
||||
size_t len = 0;
|
||||
char *res = ipc_single_command(bar->ipc_socketfd,
|
||||
IPC_GET_WORKSPACES, NULL, &len);
|
||||
if (res == NULL) {
|
||||
return false;
|
||||
}
|
||||
json_object *results = json_tokener_parse(res);
|
||||
if (!results) {
|
||||
free(res);
|
||||
|
|
@ -411,16 +414,16 @@ bool ipc_get_workspaces(struct swaybar *bar) {
|
|||
void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
|
||||
sway_log(SWAY_DEBUG, "Executing binding for button %u (release=%d): `%s`",
|
||||
bind->button, bind->release, bind->command);
|
||||
uint32_t len = strlen(bind->command);
|
||||
size_t len = strlen(bind->command);
|
||||
free(ipc_single_command(bar->ipc_socketfd,
|
||||
IPC_COMMAND, bind->command, &len));
|
||||
}
|
||||
|
||||
bool ipc_initialize(struct swaybar *bar) {
|
||||
uint32_t len = strlen(bar->id);
|
||||
size_t len = strlen(bar->id);
|
||||
char *res = ipc_single_command(bar->ipc_socketfd,
|
||||
IPC_GET_BAR_CONFIG, bar->id, &len);
|
||||
if (!ipc_parse_config(bar->config, res)) {
|
||||
if (res == NULL || !ipc_parse_config(bar->config, res)) {
|
||||
free(res);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -550,8 +550,16 @@ int main(int argc, char **argv) {
|
|||
int socketfd = ipc_open_socket(socket_path);
|
||||
struct timeval timeout = {.tv_sec = 3, .tv_usec = 0};
|
||||
ipc_set_recv_timeout(socketfd, timeout);
|
||||
uint32_t len = strlen(command);
|
||||
size_t len = strlen(command);
|
||||
char *resp = ipc_single_command(socketfd, type, command, &len);
|
||||
if (resp == NULL) {
|
||||
if (!quiet) {
|
||||
sway_log(SWAY_ERROR, "Failed to receive reply");
|
||||
}
|
||||
close(socketfd);
|
||||
free(socket_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// pretty print the json
|
||||
json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue