cpc.c (4913B)
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(void); 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 double price; 144 FILE *fp; 145 ; 146 if ((fp = fopen(file, "r")) == NULL) 147 fatal("Error opening file '%s'\n", file); 148 149 while ((getline(&line_buf, &line_buf_size, fp)) >= 0) { 150 sscanf(line_buf, "%[^;];%lf", name, &price); 151 switch (action) { 152 case AS_FIAT: 153 printf("%f %s\n", value/price, name); 154 break; 155 case AS_CRYPTO: 156 printf("(%s) %f %s\n", name, value*price, FIAT); 157 break; 158 default: 159 break; 160 } 161 } 162 163 free(line_buf); 164 165 fclose(fp); 166 } 167 168 void 169 call_api(void) 170 { 171 char libversion[20], request[strlen(URL) + strlen(FIAT) + strlen(CURRENCIES) + 1]; 172 struct curl_slist *headers = NULL; 173 Memory mem = {0}; 174 175 CURL *curl = curl_easy_init(); 176 177 if (curl) { 178 headers = curl_slist_append(headers, "Content-Type: application/json"); 179 headers = curl_slist_append(headers, "charset: utf-8"); 180 181 curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW); 182 sprintf(libversion, "curl/%u.%u.%u", 183 (ver->version_num >> 16) & 0xff, 184 (ver->version_num >> 8) & 0xff, 185 ver->version_num & 0xff); 186 sprintf(request, URL, CURRENCIES, FIAT); 187 188 CURLcode res; 189 curl_easy_setopt(curl, CURLOPT_URL, request); 190 curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); 191 curl_easy_setopt(curl, CURLOPT_USERAGENT, libversion); 192 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 193 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc); 194 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &mem); 195 curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); 196 197 res = curl_easy_perform(curl); 198 199 if (res != CURLE_OK) 200 fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); 201 else { 202 parse_json_object(mem.response); 203 printf("\n=== Updated prices ===\n"); 204 free(mem.response); 205 } 206 curl_slist_free_all(headers); 207 } 208 209 curl_easy_cleanup(curl); 210 } 211 212 char * 213 cpstr(char *dest, const char *src) 214 { 215 size_t cplen = strlen(src); 216 memcpy(dest, src, cplen); 217 dest[cplen] = '\0'; 218 return dest; 219 } 220 221 void 222 fatal(const char *fmt, ...) 223 { 224 va_list ap; 225 226 va_start(ap, fmt); 227 vfprintf(stderr, fmt, ap); 228 va_end(ap); 229 230 exit(EXIT_FAILURE); 231 }