cpc

Cryptocurrency price checker
git clone git://git.wimdupont.com/cpc.git
Log | Files | Refs | LICENSE

cpc.c (4925B)


      1 #include <stdio.h>
      2 #include <pwd.h>
      3 #include <unistd.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <cjson/cJSON.h>
      7 #include <curl/curl.h>
      8 
      9 #include "config.h"
     10 
     11 #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
     12 
     13 typedef enum {AS_FIAT, AS_CRYPTO} Action;
     14 
     15 typedef struct
     16 {
     17 	char *response;
     18 	size_t size;
     19 } Memory;
     20 
     21 static size_t writefunc(char *data, size_t size, size_t nmemb, Memory *mem);
     22 static void wfile(cJSON *array);
     23 static void parse_json_object(const char *json_string);
     24 static char * replace_home(char *buf, const char *path);
     25 static void do_action(Action action, const double value);
     26 static void call_api();
     27 static char * cpstr(char *dest, const char *src);
     28 static void fatal(const char *fmt, ...);
     29 
     30 static char file[PATH_MAX];
     31 
     32 int
     33 main(int argc, char **argv)
     34 {
     35 	int opt, update = 0;
     36 	double value = 1;
     37 	Action action = AS_CRYPTO;
     38 
     39 	replace_home(file, PRICES_FILE);
     40 
     41 	while ((opt = getopt(argc, argv, "urv:")) != -1) {
     42 		switch (opt) {
     43 			case 'u':
     44 				update = 1;
     45 				break;
     46 			case 'r':
     47 				action = AS_FIAT;
     48 				break;
     49 			case 'v':
     50 				sscanf(optarg, "%lf", &value);
     51 				break;
     52 			default:
     53 				fatal("Unknown option: %c\n", optopt);
     54 				break;
     55 		}
     56 	}
     57 
     58 	for(; optind < argc; optind++)
     59 		printf("ignored arguments: %s\n", argv[optind]);
     60 
     61 	if (update)
     62 		call_api();
     63 
     64 	do_action(action, value);
     65 }
     66 
     67 size_t
     68 writefunc(char *data, size_t size, size_t nmemb, Memory *mem)
     69 {
     70 	char *ptr;
     71 	size_t realsize = size * nmemb;
     72 	
     73 	if ((ptr = realloc(mem->response, mem->size + realsize + 1)) == NULL)
     74 		fatal("Realloc failed\n");
     75 	
     76 	mem->response = ptr;
     77 	memcpy(&(mem->response[mem->size]), data, realsize);
     78 	mem->size += realsize;
     79 	mem->response[mem->size] = 0;
     80 	
     81 	return realsize;
     82 }
     83 
     84 void
     85 wfile(cJSON *array)
     86 {
     87 	cJSON *item = array ? array->child : 0;
     88 	FILE *fp;
     89 
     90 	if ((fp = fopen(file, "w+")) == NULL)
     91 		fatal("Opening file failed: %s\n", file);
     92 
     93 	while (item) {
     94 		cJSON *name = cJSON_GetObjectItem(item, "name");
     95 		cJSON *price = cJSON_GetObjectItem(item, "current_price");
     96 		fprintf(fp, "%s;%f\n", name->valuestring, price->valuedouble);
     97 		item=item->next;
     98 	}
     99 
    100 	fclose(fp);
    101 }
    102 
    103 void
    104 parse_json_object(const char *json_string)
    105 {
    106 	cJSON *json = cJSON_Parse(json_string);
    107 
    108 	if (json == NULL) {
    109 		const char *error_ptr = cJSON_GetErrorPtr();
    110 		if (error_ptr != NULL)
    111 			fatal("Error before: %s\n", error_ptr);
    112 		return;
    113 	}
    114 	wfile(json);
    115 	cJSON_Delete(json);
    116 }
    117 
    118 char *
    119 replace_home(char *buf, const char *path)
    120 {
    121 	char *userhome, *envv = "$HOME";
    122 	struct passwd userinf;
    123 
    124 	userinf = *getpwuid(getuid());
    125 	userhome = strdup(userinf.pw_dir);
    126 
    127 	if ((strstr(path, envv) != NULL)) {
    128 		cpstr(buf, userhome);
    129 		strcat(buf, path + strlen(envv));
    130 	} else
    131 		cpstr(buf, path);
    132 
    133 	free(userhome);
    134 
    135 	return buf;
    136 }
    137 
    138 void
    139 do_action(Action action, const double value)
    140 {
    141 	char name[50], *line_buf = NULL;
    142 	size_t line_buf_size = 0;
    143 	ssize_t line_size;
    144 	double price;
    145 	FILE *fp;
    146 ;
    147 	if ((fp = fopen(file, "r")) == NULL)
    148 		fatal("Error opening file '%s'\n", file);
    149 
    150 	while ((getline(&line_buf, &line_buf_size, fp)) >= 0) {
    151 		sscanf(line_buf, "%[^;];%lf", name, &price);
    152 		switch (action) {
    153 			case AS_FIAT:
    154 				printf("%f %s\n", value/price, name);
    155 				break;
    156 			case AS_CRYPTO:
    157 				printf("(%s) %f %s\n", name, value*price, FIAT);
    158 				break;
    159 			default:
    160 				break;
    161 		}
    162 	}
    163 
    164 	free(line_buf);
    165 
    166 	fclose(fp);
    167 }
    168 
    169 void
    170 call_api()
    171 {
    172 	char libversion[20], request[strlen(URL) + strlen(FIAT) + strlen(CURRENCIES) + 1];
    173 	struct curl_slist *headers = NULL;
    174 	Memory mem = {0};
    175 
    176 	CURL *curl = curl_easy_init();
    177 
    178 	if (curl) {
    179 		headers = curl_slist_append(headers, "Content-Type: application/json");
    180 		headers = curl_slist_append(headers, "charset: utf-8");
    181 
    182 		curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
    183 		sprintf(libversion, "curl/%u.%u.%u",
    184 				(ver->version_num >> 16) & 0xff,
    185 				(ver->version_num >> 8) & 0xff,
    186 				ver->version_num & 0xff);
    187 		sprintf(request, URL, CURRENCIES, FIAT);
    188 
    189 		CURLcode res;
    190 		curl_easy_setopt(curl, CURLOPT_URL, request);
    191 		curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
    192 		curl_easy_setopt(curl, CURLOPT_USERAGENT, libversion);
    193 		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    194  		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
    195 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &mem);
    196 		curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
    197 
    198 		res = curl_easy_perform(curl);
    199 
    200 		if (res != CURLE_OK)
    201 			fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
    202 		else {
    203 			parse_json_object(mem.response);
    204 			printf("\n=== Updated prices ===\n");
    205 			free(mem.response);
    206 		}
    207 		curl_slist_free_all(headers);
    208 	}
    209 
    210 	curl_easy_cleanup(curl);
    211 }
    212 
    213 char *
    214 cpstr(char *dest, const char *src)
    215 {
    216 	size_t cplen = strlen(src);
    217 	memcpy(dest, src, cplen);
    218 	dest[cplen] = '\0';
    219 	return dest;
    220 }
    221 
    222 void
    223 fatal(const char *fmt, ...)
    224 {
    225 	va_list ap;
    226 
    227 	va_start(ap, fmt);
    228 	vfprintf(stderr, fmt, ap);
    229 	va_end(ap);
    230 
    231 	exit(EXIT_FAILURE);
    232 }