mirror of https://github.com/r4sas/pbincli-cpp
R4SAS
5 years ago
3 changed files with 568 additions and 0 deletions
@ -0,0 +1,530 @@ |
|||||||
|
#include <fstream> |
||||||
|
#include <iostream> |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <getopt.h> |
||||||
|
|
||||||
|
#include <jansson.h> |
||||||
|
#include <curl/curl.h> |
||||||
|
|
||||||
|
#include "main.h" |
||||||
|
|
||||||
|
CURL *curl; |
||||||
|
|
||||||
|
bool opt_debug = false; |
||||||
|
bool opt_notext = false; |
||||||
|
bool opt_nocertcheck = false; |
||||||
|
|
||||||
|
const char *opt_server = "https://paste.i2pd.xyz/"; |
||||||
|
char *opt_proxy; |
||||||
|
long opt_proxy_type; |
||||||
|
static json_t *opt_config; |
||||||
|
|
||||||
|
struct upload_buffer { |
||||||
|
const void *buf; |
||||||
|
size_t len; |
||||||
|
size_t pos; |
||||||
|
}; |
||||||
|
|
||||||
|
enum paste_command { |
||||||
|
PASTE_SEND = 1, |
||||||
|
PASTE_GET, |
||||||
|
PASTE_DELETE |
||||||
|
}; |
||||||
|
|
||||||
|
int paste_mode = 0; |
||||||
|
|
||||||
|
std::string paste_message; |
||||||
|
char *paste_filepath; |
||||||
|
char *paste_password; |
||||||
|
|
||||||
|
const char *paste_expire = "1day"; |
||||||
|
bool paste_burn = false; |
||||||
|
bool paste_discus = false; |
||||||
|
|
||||||
|
const char *paste_format = "plaintext"; |
||||||
|
|
||||||
|
char *paste_id; |
||||||
|
char *paste_token; |
||||||
|
|
||||||
|
static char const usage[] = "\
|
||||||
|
Usage: " PROGRAM_NAME " [OPTIONS] <COMMAND> [paste_id | paste_id#paste_key]\n\ |
||||||
|
Available commands:\n\ |
||||||
|
send Send paste\n\ |
||||||
|
get Receive paste\n\ |
||||||
|
delete Delete paste\n\ |
||||||
|
\n\ |
||||||
|
Global options:\n\ |
||||||
|
-s, --server=[PROTOCOL://]HOST[:PORT]/[PATH/]\n\ |
||||||
|
Change used server address\n\ |
||||||
|
-x, --proxy=[PROTOCOL://]HOST[:PORT]\n\ |
||||||
|
connect through a proxy\n\ |
||||||
|
--no-check-certificate\n\ |
||||||
|
do not verify server certificate\n\ |
||||||
|
-d, --debug enable debugging output\n\ |
||||||
|
-c, --config=FILE load a JSON-format configuration file\n\ |
||||||
|
-V, --version display version information and exit\n\ |
||||||
|
-h, --help display this help text and exit\n\ |
||||||
|
\n\ |
||||||
|
'send' command options:\n\ |
||||||
|
" PROGRAM_NAME " [-m text] [...] send\n\ |
||||||
|
-m, --message=<TEXT> text to add in paste written in quotes.\n\ |
||||||
|
If not set, text will be read from stdin\n\ |
||||||
|
-f, --file=<FILE> path to file to attach to paste\n\ |
||||||
|
example: /home/user/document.pdf\n\ |
||||||
|
-p --password=<PASSWORD>\n\ |
||||||
|
password for encrypting paste\n\ |
||||||
|
-E --expire=<5min|10min|1hour|1day|1week|1month|1year|never>\n\ |
||||||
|
paste lifetime (default: 1day)\n\ |
||||||
|
-B --burn burn sent paste after reading\n\ |
||||||
|
-D --discus open discussion for sent paste\n\ |
||||||
|
-F --format=<plaintext|syntaxhighlighting|markdown>\n\ |
||||||
|
format of text (default: plaintext)\n\ |
||||||
|
-q --notext disable text store for paste. If used,\n\ |
||||||
|
--file will be required to be selected!\n\ |
||||||
|
-C --compression=<zlib|none>\n\ |
||||||
|
paste compression mode (default: zlib)\n\ |
||||||
|
\n\ |
||||||
|
'get ' command options:\n\ |
||||||
|
" PROGRAM_NAME " [-p password] get <paste_id#paste_key>\n\ |
||||||
|
-p --password=pass password for decrypting paste\n\ |
||||||
|
paste_id#paste_key id and key pair of paste\n\ |
||||||
|
\n\ |
||||||
|
'delete' command options:\n\ |
||||||
|
" PROGRAM_NAME " <-t token> delete <paste_id>\n\ |
||||||
|
-t --token=<TOKEN> password for decrypting paste\n\ |
||||||
|
paste_id id and key pair of paste\n\ |
||||||
|
"; |
||||||
|
|
||||||
|
static char const short_options[] = |
||||||
|
"m:f:p:E:BDF:qC:t:s:x:dc:Vh"; |
||||||
|
|
||||||
|
static struct option options[] = { |
||||||
|
{ "message", required_argument, NULL, 'm' }, |
||||||
|
{ "file", required_argument, NULL, 'f' }, |
||||||
|
{ "password", required_argument, NULL, 'p' }, |
||||||
|
{ "expire", required_argument, NULL, 'E' }, |
||||||
|
{ "burn", no_argument, NULL, 'B' }, |
||||||
|
{ "discus", no_argument, NULL, 'D' }, |
||||||
|
{ "format", required_argument, NULL, 'F' }, |
||||||
|
{ "notext", no_argument, NULL, 'q' }, |
||||||
|
{ "compression", required_argument, NULL, 'C' }, |
||||||
|
{ "token", required_argument, NULL, 't' }, |
||||||
|
{ "paste", required_argument, NULL, 1000 }, |
||||||
|
{ "no-check-certificate", no_argument, NULL, 1001 }, |
||||||
|
{ "host", required_argument, NULL, 's' }, |
||||||
|
{ "proxy", required_argument, NULL, 'x' }, |
||||||
|
{ "debug", no_argument, NULL, 'd' }, |
||||||
|
{ "config", required_argument, NULL, 'c' }, |
||||||
|
{ "version", no_argument, NULL, 'V' }, |
||||||
|
{ "help", no_argument, NULL, 'h' }, |
||||||
|
{ NULL, 0, NULL, 0 } |
||||||
|
}; |
||||||
|
|
||||||
|
static void show_version_and_exit(void) |
||||||
|
{ |
||||||
|
printf("%s v%s\n" |
||||||
|
"%s\n", |
||||||
|
PACKAGE_NAME, PACKAGE_VERSION, |
||||||
|
curl_version()); |
||||||
|
exit(EXIT_SUCCESS); |
||||||
|
} |
||||||
|
|
||||||
|
static void show_usage_and_exit(int status) |
||||||
|
{ |
||||||
|
if (status) |
||||||
|
fprintf(stderr, "Try `" PROGRAM_NAME " --help' for more information.\n"); |
||||||
|
else |
||||||
|
printf(usage); |
||||||
|
|
||||||
|
exit(status); |
||||||
|
} |
||||||
|
|
||||||
|
void parse_arg(int key, char *arg) |
||||||
|
{ |
||||||
|
switch(key) { |
||||||
|
case 'm': |
||||||
|
paste_message = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'f': |
||||||
|
free(paste_filepath); |
||||||
|
paste_filepath = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'p': |
||||||
|
free(paste_password); |
||||||
|
paste_password = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'E': |
||||||
|
// here provided only default values
|
||||||
|
if (!strcasecmp(arg, "5min") || !strcasecmp(arg, "10min") || !strcasecmp(arg, "1hour") || !strcasecmp(arg, "1day") || |
||||||
|
!strcasecmp(arg, "1week") || !strcasecmp(arg, "1month") || !strcasecmp(arg, "1year") || !strcasecmp(arg, "never")) |
||||||
|
paste_expire = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'B': |
||||||
|
paste_burn = true; |
||||||
|
break; |
||||||
|
|
||||||
|
case 'D': |
||||||
|
paste_discus = true; |
||||||
|
break; |
||||||
|
|
||||||
|
case 'F': |
||||||
|
// here provided only default values
|
||||||
|
if (!strcasecmp(arg, "plaintext") || !strcasecmp(arg, "syntaxhighlighting") || !strcasecmp(arg, "markdown")) |
||||||
|
paste_format = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'q': |
||||||
|
opt_notext = true; |
||||||
|
break; |
||||||
|
|
||||||
|
case 1000: |
||||||
|
free(paste_id); |
||||||
|
paste_id = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 't': |
||||||
|
free(paste_token); |
||||||
|
paste_token = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 1001: |
||||||
|
opt_nocertcheck = true; |
||||||
|
break; |
||||||
|
|
||||||
|
case 's': |
||||||
|
opt_server = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'x': |
||||||
|
if (!strncasecmp(arg, "socks4://", 9)) |
||||||
|
opt_proxy_type = CURLPROXY_SOCKS4; |
||||||
|
else if (!strncasecmp(arg, "socks5://", 9)) |
||||||
|
opt_proxy_type = CURLPROXY_SOCKS5; |
||||||
|
#if LIBCURL_VERSION_NUM >= 0x071200 |
||||||
|
else if (!strncasecmp(arg, "socks4a://", 10)) |
||||||
|
opt_proxy_type = CURLPROXY_SOCKS4A; |
||||||
|
else if (!strncasecmp(arg, "socks5h://", 10)) |
||||||
|
opt_proxy_type = CURLPROXY_SOCKS5_HOSTNAME; |
||||||
|
#endif |
||||||
|
else |
||||||
|
opt_proxy_type = CURLPROXY_HTTP; |
||||||
|
free(opt_proxy); |
||||||
|
opt_proxy = strdup(arg); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'c': |
||||||
|
json_error_t err; |
||||||
|
if (opt_config) { |
||||||
|
json_decref(opt_config); |
||||||
|
opt_config = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
opt_config = JSON_LOADF(arg, &err); |
||||||
|
|
||||||
|
if (!json_is_object(opt_config)) { |
||||||
|
fprintf(stderr, "JSON decode of %s failed", arg); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
break; |
||||||
|
|
||||||
|
case 'd': |
||||||
|
opt_debug = true; |
||||||
|
break; |
||||||
|
|
||||||
|
case 'V': |
||||||
|
show_version_and_exit(); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'h': |
||||||
|
show_usage_and_exit(EXIT_SUCCESS); |
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
show_usage_and_exit(EXIT_FAILURE); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void parse_config(json_t* json_obj) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
json_t *val; |
||||||
|
|
||||||
|
if (!json_is_object(json_obj)) |
||||||
|
return; |
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(options); i++) { |
||||||
|
|
||||||
|
if (!options[i].name) |
||||||
|
break; |
||||||
|
|
||||||
|
if (!strcasecmp(options[i].name, "config")) |
||||||
|
continue; |
||||||
|
|
||||||
|
val = json_object_get(json_obj, options[i].name); |
||||||
|
if (!val) |
||||||
|
continue; |
||||||
|
|
||||||
|
if (options[i].has_arg && json_is_string(val)) { |
||||||
|
char *s = strdup(json_string_value(val)); |
||||||
|
if (!s) |
||||||
|
continue; |
||||||
|
parse_arg(options[i].val, s); |
||||||
|
free(s); |
||||||
|
} |
||||||
|
else if (options[i].has_arg && json_is_integer(val)) { |
||||||
|
char buf[16]; |
||||||
|
sprintf(buf, "%d", (int) json_integer_value(val)); |
||||||
|
parse_arg(options[i].val, buf); |
||||||
|
} |
||||||
|
else if (options[i].has_arg && json_is_real(val)) { |
||||||
|
char buf[16]; |
||||||
|
sprintf(buf, "%f", json_real_value(val)); |
||||||
|
parse_arg(options[i].val, buf); |
||||||
|
} |
||||||
|
else if (!options[i].has_arg) { |
||||||
|
if (json_is_true(val)) |
||||||
|
parse_arg(options[i].val, (char*) ""); |
||||||
|
} |
||||||
|
else |
||||||
|
fprintf(stderr, "JSON option %s invalid", options[i].name); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
size_t all_data_cb(char *contents, size_t size, size_t nmemb, void *userp) |
||||||
|
{ |
||||||
|
((std::string*)userp)->append((char*)contents, size * nmemb); |
||||||
|
return size * nmemb; |
||||||
|
} |
||||||
|
|
||||||
|
static json_t *json_server_call(CURL *curl, const char *url, const char *req, int *curl_err) |
||||||
|
{ |
||||||
|
json_t *val, *err_val, *res_val; |
||||||
|
int rc; |
||||||
|
std::string all_data; |
||||||
|
struct upload_buffer upload_data; |
||||||
|
json_error_t err; |
||||||
|
struct curl_slist *headers = NULL; |
||||||
|
char *httpdata; |
||||||
|
char len_hdr[64]; |
||||||
|
char curl_err_str[CURL_ERROR_SIZE] = { 0 }; |
||||||
|
|
||||||
|
/* it is assumed that 'curl' is freshly [re]initialized at this pt */ |
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, url); |
||||||
|
if (opt_nocertcheck) { |
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); |
||||||
|
} |
||||||
|
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0); |
||||||
|
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); |
||||||
|
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); |
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, all_data_cb); |
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &all_data); |
||||||
|
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str); |
||||||
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); |
||||||
|
if (opt_proxy) { |
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXY, opt_proxy); |
||||||
|
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, opt_proxy_type); |
||||||
|
} |
||||||
|
|
||||||
|
switch (paste_mode) { |
||||||
|
case PASTE_SEND: |
||||||
|
case PASTE_DELETE: |
||||||
|
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_data); |
||||||
|
curl_easy_setopt(curl, CURLOPT_POST, 1); |
||||||
|
upload_data.buf = req; |
||||||
|
upload_data.len = strlen(req); |
||||||
|
upload_data.pos = 0; |
||||||
|
sprintf(len_hdr, "Content-Length: %lu", (unsigned long) upload_data.len); |
||||||
|
headers = curl_slist_append(headers, "Content-Type: application/json"); |
||||||
|
headers = curl_slist_append(headers, len_hdr); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
headers = curl_slist_append(headers, "X-Requested-With: JSONHttpRequest"); |
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); |
||||||
|
|
||||||
|
rc = curl_easy_perform(curl); |
||||||
|
if (curl_err != NULL) |
||||||
|
*curl_err = rc; |
||||||
|
if (rc != CURLE_OK) { |
||||||
|
if (rc != CURLE_OPERATION_TIMEDOUT) { |
||||||
|
fprintf(stderr, "HTTP request failed: %s", curl_err_str); |
||||||
|
goto err_out; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!all_data.length()) { |
||||||
|
fprintf(stderr, "Empty data received in json_rpc_call."); |
||||||
|
goto err_out; |
||||||
|
} |
||||||
|
|
||||||
|
httpdata = (char*) all_data.c_str(); |
||||||
|
|
||||||
|
std::cout << httpdata << std::endl; |
||||||
|
|
||||||
|
val = JSON_LOADS(httpdata, &err); |
||||||
|
if (!val) { |
||||||
|
fprintf(stderr, "JSON decode failed(%d): %s", err.line, err.text); |
||||||
|
goto err_out; |
||||||
|
} |
||||||
|
|
||||||
|
curl_slist_free_all(headers); |
||||||
|
curl_easy_reset(curl); |
||||||
|
return val; |
||||||
|
|
||||||
|
err_out: |
||||||
|
curl_slist_free_all(headers); |
||||||
|
curl_easy_reset(curl); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
static void parse_cmdline(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
int key; |
||||||
|
|
||||||
|
while ((key = getopt_long(argc, argv, short_options, options, NULL)) != -1) { |
||||||
|
parse_arg(key, optarg); |
||||||
|
} |
||||||
|
|
||||||
|
parse_config(opt_config); |
||||||
|
} |
||||||
|
|
||||||
|
static void initialize_curl() |
||||||
|
{ |
||||||
|
long flags; |
||||||
|
|
||||||
|
// cURL initialization
|
||||||
|
flags = strncmp(opt_server, "https:", 6) |
||||||
|
? (CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL) |
||||||
|
: CURL_GLOBAL_ALL; |
||||||
|
if (curl_global_init(flags)) { |
||||||
|
fprintf(stderr, "CURL initialization failed"); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} else { |
||||||
|
curl = curl_easy_init(); |
||||||
|
if (unlikely(!curl)) { |
||||||
|
fprintf(stderr, "CURL initialization failed"); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// ### main ###
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) |
||||||
|
{ |
||||||
|
json_t *resp = NULL; |
||||||
|
int err = 0; |
||||||
|
|
||||||
|
parse_cmdline(argc, argv); |
||||||
|
|
||||||
|
if (optind >= argc) { |
||||||
|
fprintf(stderr, "%s: command not specified! (see --help)\n", PROGRAM_NAME); |
||||||
|
return EXIT_FAILURE; |
||||||
|
} |
||||||
|
|
||||||
|
// Program mode changer
|
||||||
|
if (!strcasecmp(argv[optind], "send")) |
||||||
|
paste_mode = PASTE_SEND; |
||||||
|
else if (!strcasecmp(argv[optind], "get")) |
||||||
|
paste_mode = PASTE_GET; |
||||||
|
else if (!strcasecmp(argv[optind], "delete")) |
||||||
|
paste_mode = PASTE_DELETE; |
||||||
|
else { |
||||||
|
fprintf(stderr, "%s: unknown command specified! (see --help)\n", PROGRAM_NAME); |
||||||
|
return EXIT_FAILURE; |
||||||
|
} |
||||||
|
// increase options index for additional info
|
||||||
|
optind++; |
||||||
|
|
||||||
|
printf("===== %s =====\n", PROGRAM_NAME); |
||||||
|
|
||||||
|
if (paste_mode == PASTE_SEND) { |
||||||
|
if(paste_message.length()) { |
||||||
|
printf("Received text: %s\n", paste_message.c_str()); |
||||||
|
} else if(!opt_notext) { |
||||||
|
printf("No text is received, so reading it from stdin...\n"); |
||||||
|
while (std::getline(std::cin, paste_message)){ } |
||||||
|
printf("Received text: %s\n", paste_message.c_str()); |
||||||
|
} |
||||||
|
|
||||||
|
printf("Format: %s", paste_format); |
||||||
|
|
||||||
|
} else if (paste_mode == PASTE_GET) { |
||||||
|
CURLU *h; |
||||||
|
CURLUcode uc; |
||||||
|
|
||||||
|
std::string pasteData; |
||||||
|
std::string pasteID; |
||||||
|
std::string pasteKey; |
||||||
|
std::string pasteUrl; |
||||||
|
|
||||||
|
// reading paste id and key from argv
|
||||||
|
if (optind >= argc) { // if paste info is not specified
|
||||||
|
fprintf(stderr, "%s: paste information is not provided! (see --help)\n", PROGRAM_NAME); |
||||||
|
return EXIT_FAILURE; |
||||||
|
} else |
||||||
|
pasteData = strdup(argv[optind]); |
||||||
|
|
||||||
|
// validate that received value is not full URL
|
||||||
|
h = curl_url(); /* get a handle to work with */ |
||||||
|
if(!h) |
||||||
|
return EXIT_FAILURE; |
||||||
|
|
||||||
|
/* parse a full URL */ |
||||||
|
uc = curl_url_set(h, CURLUPART_URL, pasteData.c_str(), 0); |
||||||
|
if(uc) // if that is not URL
|
||||||
|
{ |
||||||
|
std::cout << "That is not URL" << std::endl; |
||||||
|
|
||||||
|
size_t pos = pasteData.find('#'); |
||||||
|
if (pos != std::string::npos) { |
||||||
|
pasteID = pasteData.substr(0, pos++); |
||||||
|
pasteKey = pasteData.substr(pos); |
||||||
|
} else { |
||||||
|
fprintf(stderr, "%s: received paste information is not looks like needed! (see --help)\n", PROGRAM_NAME); |
||||||
|
return EXIT_FAILURE; |
||||||
|
} |
||||||
|
|
||||||
|
pasteUrl = std::string(opt_server) + "?" + std::string(pasteID); |
||||||
|
std::cout << "At the end we have URL \"" << pasteUrl << "\" with key " << pasteKey << std::endl; |
||||||
|
|
||||||
|
} else { |
||||||
|
std::cout << "This is URL" << std::endl; |
||||||
|
|
||||||
|
size_t pos = pasteData.find('#'); |
||||||
|
if (pos != std::string::npos) { |
||||||
|
pasteUrl = pasteData.substr(0, pos++); |
||||||
|
pasteKey = pasteData.substr(pos); |
||||||
|
|
||||||
|
size_t pos = pasteData.find('?'); |
||||||
|
if (pos != std::string::npos) { |
||||||
|
opt_server = pasteData.substr(0, pos++).c_str(); |
||||||
|
} else { |
||||||
|
fprintf(stderr, "%s: can't find a request option separator \"?\" in URL! (see --help)\n", PROGRAM_NAME); |
||||||
|
return EXIT_FAILURE; |
||||||
|
} |
||||||
|
} else { |
||||||
|
fprintf(stderr, "%s: can't find a \"#\" delimiter in URL! (see --help)\n", PROGRAM_NAME); |
||||||
|
return EXIT_FAILURE; |
||||||
|
} |
||||||
|
} |
||||||
|
curl_url_cleanup(h); |
||||||
|
|
||||||
|
initialize_curl(); |
||||||
|
|
||||||
|
std::cout << "Requesting data from " << pasteUrl << "...\n"; |
||||||
|
resp = json_server_call(curl, pasteUrl.c_str(), NULL, &err); |
||||||
|
std::cout << resp; |
||||||
|
} else if (paste_mode == PASTE_DELETE) { |
||||||
|
// todo
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
#ifndef MAIN_H__ |
||||||
|
#define MAIN_H__ |
||||||
|
|
||||||
|
#define PROGRAM_NAME "pbincli" |
||||||
|
#define PACKAGE "pbincli" |
||||||
|
#define PACKAGE_BUGREPORT "" |
||||||
|
#define PACKAGE_NAME "pbincli" |
||||||
|
#define PACKAGE_URL "https://github.com/r4sas/pbincli-c++"
|
||||||
|
#define PACKAGE_VERSION "0.1" |
||||||
|
|
||||||
|
#if JANSSON_MAJOR_VERSION >= 2 |
||||||
|
#define JSON_LOADS(str, err_ptr) json_loads((str), 0, (err_ptr)) |
||||||
|
#define JSON_LOADF(str, err_ptr) json_load_file((str), 0, (err_ptr)) |
||||||
|
#else |
||||||
|
#define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr)) |
||||||
|
#define JSON_LOADF(str, err_ptr) json_load_file((str), (err_ptr)) |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef ARRAY_SIZE |
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) |
||||||
|
#endif |
||||||
|
|
||||||
|
#undef unlikely |
||||||
|
#undef likely |
||||||
|
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) |
||||||
|
#define unlikely(expr) (__builtin_expect(!!(expr), 0)) |
||||||
|
#define likely(expr) (__builtin_expect(!!(expr), 1)) |
||||||
|
#else |
||||||
|
#define unlikely(expr) (expr) |
||||||
|
#define likely(expr) (expr) |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue