1 diff --git a/cower.c b/cower.c
2 index 03e1256..9382d3c 100644
6 #define STREQ(x,y) (strcmp((x),(y)) == 0)
7 #define STR_STARTS_WITH(x,y) (strncmp((x),(y), strlen(y)) == 0)
8 #define NCFLAG(val, flag) (!cfg.color && (val)) ? (flag) : ""
9 +#define KEY_IS(k) (strncmp(p->key, (k), p->keysz) == 0)
11 #define COWER_USERAGENT "cower/3.x"
14 #define AUR_QUERY_TYPE_SEARCH "search"
15 #define AUR_QUERY_TYPE_MSRCH "msearch"
16 #define AUR_QUERY_ERROR "error"
17 +#define AUR_QUERY_RESULTCOUNT "resultcount"
20 #define VERSION "Version"
21 @@ -195,32 +197,33 @@ struct strings_t {
47 + alpm_list_t *conflicts;
49 alpm_list_t *makedepends;
50 alpm_list_t *optdepends;
51 alpm_list_t *provides;
52 - alpm_list_t *conflicts;
53 alpm_list_t *replaces;
56 struct yajl_parser_t {
59 struct aurpkg_t *aurpkg;
66 @@ -247,8 +250,8 @@ static int alpm_pkg_is_foreign(pmpkg_t*);
67 static const char *alpm_provides_pkg(const char*);
68 static int archive_extract_file(const struct response_t*);
69 static int aurpkg_cmp(const void*, const void*);
70 +static struct aurpkg_t *aurpkg_dup(const struct aurpkg_t *pkg);
71 static void aurpkg_free(void*);
72 -static struct aurpkg_t *aurpkg_new(void);
73 static CURL *curl_init_easy_handle(CURL*);
74 static char *curl_get_url_as_buffer(CURL*, const char*);
75 static size_t curl_write_response(void*, size_t, size_t, void*);
76 @@ -261,6 +264,7 @@ static char *get_file_as_buffer(const char*);
77 static int getcols(void);
78 static void indentprint(const char*, int);
79 static int json_end_map(void*);
80 +static int json_integer(void *ctx, long long val);
81 static int json_map_key(void*, const unsigned char*, size_t);
82 static int json_start_map(void*);
83 static int json_string(void*, const unsigned char*, size_t);
84 @@ -327,7 +331,7 @@ struct openssl_mutex_t openssl_lock;
85 static yajl_callbacks callbacks = {
89 + json_integer, /* integer */
92 json_string, /* string */
93 @@ -502,6 +506,16 @@ int aurpkg_cmp(const void *p1, const void *p2) { /* {{{ */
94 return strcmp((const char*)pkg1->name, (const char*)pkg2->name);
97 +struct aurpkg_t *aurpkg_dup(const struct aurpkg_t *pkg) /* {{{ */
99 + struct aurpkg_t *newpkg;
101 + MALLOC(newpkg, sizeof(struct aurpkg_t), return NULL);
102 + memcpy(newpkg, pkg, sizeof(struct aurpkg_t));
107 void aurpkg_free(void *pkg) { /* {{{ */
110 @@ -511,14 +525,12 @@ void aurpkg_free(void *pkg) { /* {{{ */
112 it = (struct aurpkg_t*)pkg;
123 FREELIST(it->depends);
124 FREELIST(it->makedepends);
125 @@ -530,14 +542,6 @@ void aurpkg_free(void *pkg) { /* {{{ */
129 -struct aurpkg_t *aurpkg_new() { /* {{{ */
130 - struct aurpkg_t *pkg;
132 - CALLOC(pkg, 1, sizeof *pkg, return NULL);
137 int cwr_asprintf(char **string, const char *format, ...) { /* {{{ */
140 @@ -823,77 +827,113 @@ void indentprint(const char *str, int indent) { /* {{{ */
144 -int json_end_map(void *ctx) { /* {{{ */
145 - struct yajl_parser_t *parse_struct = (struct yajl_parser_t*)ctx;
146 +int json_end_map(void *ctx) /* {{{ */
148 + struct yajl_parser_t *p = (struct yajl_parser_t*)ctx;
150 - if (--parse_struct->json_depth > 0) {
151 - parse_struct->pkglist = alpm_list_add_sorted(parse_struct->pkglist,
152 - parse_struct->aurpkg, aurpkg_cmp);
155 + if(p->json_depth > 0) {
156 + p->pkglist = alpm_list_add_sorted(p->pkglist, aurpkg_dup(p->aurpkg), aurpkg_cmp);
163 -int json_map_key(void *ctx, const unsigned char *data, size_t size) { /* {{{ */
164 - struct yajl_parser_t *parse_struct = (struct yajl_parser_t*)ctx;
166 - strncpy(parse_struct->curkey, (const char*)data, size);
167 - parse_struct->curkey[size] = '\0';
170 +int json_integer(void *ctx, long long val) /* {{{ */
172 + struct yajl_parser_t *p = (struct yajl_parser_t*)ctx;
174 + if(KEY_IS(AUR_ID)) {
175 + p->aurpkg->id = (int)val;
176 + } else if(KEY_IS(AUR_CAT)) {
177 + p->aurpkg->cat = (int)val;
178 + } else if(KEY_IS(AUR_VOTES)) {
179 + p->aurpkg->votes = (int)val;
180 + } else if(KEY_IS(AUR_OOD)) {
181 + p->aurpkg->ood = (int)val;
182 + } else if(KEY_IS(AUR_FIRSTSUB)) {
183 + p->aurpkg->firstsub = (time_t)val;
184 + } else if(KEY_IS(AUR_LASTMOD)) {
185 + p->aurpkg->lastmod = (time_t)val;
186 + } else if(KEY_IS(AUR_QUERY_RESULTCOUNT)) {
187 + p->resultcount = (int)val;
193 -int json_start_map(void *ctx) { /* {{{ */
194 - struct yajl_parser_t *parse_struct = (struct yajl_parser_t*)ctx;
195 +int json_map_key(void *ctx, const unsigned char *data, size_t size) /* {{{ */
197 + struct yajl_parser_t *p = (struct yajl_parser_t*)ctx;
199 - if (parse_struct->json_depth++ >= 1) {
200 - parse_struct->aurpkg = aurpkg_new();
203 + memcpy(p->key, (const char*)data, size);
204 + p->key[size] = '\0';
210 -int json_string(void *ctx, const unsigned char *data, size_t size) { /* {{{ */
211 - struct yajl_parser_t *parse_struct = (struct yajl_parser_t*)ctx;
212 - const char *val = (const char*)data;
214 +int json_start_map(void *ctx) /* {{{ */
216 + struct yajl_parser_t *p = (struct yajl_parser_t*)ctx;
218 - if (STREQ(parse_struct->curkey, AUR_QUERY_TYPE) &&
219 - STR_STARTS_WITH(val, AUR_QUERY_ERROR)) {
223 + if(p->json_depth > 1) {
224 + memset(p->aurpkg, 0, sizeof(struct aurpkg_t));
227 - if (STREQ(parse_struct->curkey, AUR_ID)) {
228 - parse_struct->aurpkg->id = strndup(val, size);
229 - } else if (STREQ(parse_struct->curkey, NAME)) {
230 - parse_struct->aurpkg->name = strndup(val, size);
231 - } else if (STREQ(parse_struct->curkey, PKG_MAINT)) {
232 - parse_struct->aurpkg->maint = strndup(val, size);
233 - } else if (STREQ(parse_struct->curkey, VERSION)) {
234 - parse_struct->aurpkg->ver = strndup(val, size);
235 - } else if (STREQ(parse_struct->curkey, AUR_CAT)) {
236 - parse_struct->aurpkg->cat = atoi(val);
237 - } else if (STREQ(parse_struct->curkey, AUR_DESC)) {
238 - parse_struct->aurpkg->desc = strndup(val, size);
239 - } else if (STREQ(parse_struct->curkey, URL)) {
240 - parse_struct->aurpkg->url = strndup(val, size);
241 - } else if (STREQ(parse_struct->curkey, URLPATH)) {
242 - parse_struct->aurpkg->urlpath = strndup(val, size);
243 - } else if (STREQ(parse_struct->curkey, AUR_LICENSE)) {
244 - parse_struct->aurpkg->lic = strndup(val, size);
245 - } else if (STREQ(parse_struct->curkey, AUR_VOTES)) {
246 - parse_struct->aurpkg->votes = strndup(val, size);
247 - } else if (STREQ(parse_struct->curkey, AUR_OOD)) {
248 - parse_struct->aurpkg->ood = strncmp(val, "1", 1) == 0 ? 1 : 0;
249 - } else if (STREQ(parse_struct->curkey, AUR_FIRSTSUB)) {
250 - snprintf(buffer, size + 1, "%s", val);
251 - parse_struct->aurpkg->firstsub = strtol(buffer, NULL, 10);
252 - } else if (STREQ(parse_struct->curkey, AUR_LASTMOD)) {
253 - snprintf(buffer, size + 1, "%s", val);
254 - parse_struct->aurpkg->lastmod = strtol(buffer, NULL, 10);
260 +int json_string(void *ctx, const unsigned char *data, size_t size) /* {{{ */
262 + struct yajl_parser_t *p = (struct yajl_parser_t*)ctx;
265 + if(KEY_IS(AUR_QUERY_TYPE) &&
266 + STR_STARTS_WITH((const char*)data, AUR_QUERY_ERROR)) {
270 +#define VALDUPE(dest, src, n) \
271 + dest = malloc(n + 1); \
272 + memcpy(dest, src, n); \
275 +#define NUMCOPY(dest, src, n) \
276 + memcpy(buffer, src, n); \
277 + buffer[n] = '\0'; \
278 + dest = strtol(buffer, NULL, 10);
280 + if(KEY_IS(AUR_ID)) {
281 + NUMCOPY(p->aurpkg->id, data, size);
282 + } else if(KEY_IS(NAME)) {
283 + VALDUPE(p->aurpkg->name, data, size);
284 + } else if(KEY_IS(PKG_MAINT)) {
285 + VALDUPE(p->aurpkg->maint, data, size);
286 + } else if(KEY_IS(VERSION)) {
287 + VALDUPE(p->aurpkg->ver, data, size);
288 + } else if(KEY_IS(AUR_CAT)) {
289 + NUMCOPY(p->aurpkg->cat, data, size);
290 + } else if(KEY_IS(AUR_DESC)) {
291 + VALDUPE(p->aurpkg->desc, data, size);
292 + } else if(KEY_IS(URL)) {
293 + VALDUPE(p->aurpkg->url, data, size);
294 + } else if(KEY_IS(URLPATH)) {
295 + VALDUPE(p->aurpkg->urlpath, data, size);
296 + } else if(KEY_IS(AUR_LICENSE)) {
297 + VALDUPE(p->aurpkg->lic, data, size);
298 + } else if(KEY_IS(AUR_VOTES)) {
299 + NUMCOPY(p->aurpkg->votes, data, size);
300 + } else if(KEY_IS(AUR_OOD)) {
301 + p->aurpkg->ood = *data - 48;
302 + } else if(KEY_IS(AUR_FIRSTSUB)) {
303 + NUMCOPY(p->aurpkg->firstsub, data, size);
304 + } else if(KEY_IS(AUR_LASTMOD)) {
305 + NUMCOPY(p->aurpkg->lastmod, data, size);
311 void openssl_crypto_cleanup() { /* {{{ */
312 @@ -1443,22 +1483,23 @@ void print_extinfo_list(alpm_list_t *list, const char *fieldname, const char *de
316 -void print_pkg_formatted(struct aurpkg_t *pkg) { /* {{{ */
317 +void print_pkg_formatted(struct aurpkg_t *pkg) /* {{{ */
320 char fmt[32], buf[64];
323 end = rawmemchr(cfg.format, '\0');
325 - for (p = cfg.format; p < end; p++) {
326 + for(p = cfg.format; p < end; p++) {
330 len = strspn(p + 1 + len, printf_flags);
331 len += strspn(p + 1 + len, digits);
332 snprintf(fmt, len + 3, "%ss", p);
337 /* simple attributes */
339 snprintf(buf, 64, "%ld", pkg->lastmod);
340 @@ -1471,22 +1512,24 @@ void print_pkg_formatted(struct aurpkg_t *pkg) { /* {{{ */
341 printf(fmt, pkg->desc);
344 - printf(fmt, pkg->id);
345 + snprintf(buf, 64, "%d", pkg->id);
349 printf(fmt, pkg->lic);
352 - printf(fmt, pkg->maint);
353 + printf(fmt, pkg->maint ? pkg->maint : "(orphan)");
356 printf(fmt, pkg->name);
359 - printf(fmt, pkg->votes);
360 + snprintf(buf, 64, "%d", pkg->votes);
364 - snprintf(buf, 64, AUR_PKG_URL_FORMAT "%s", cfg.proto, pkg->id);
365 + snprintf(buf, 64, AUR_PKG_URL_FORMAT "%d", cfg.proto, pkg->id);
369 @@ -1522,48 +1565,49 @@ void print_pkg_formatted(struct aurpkg_t *pkg) { /* {{{ */
370 print_extinfo_list(pkg->replaces, NULL, cfg.delim, 0);
374 + fputc('%', stdout);
378 + fputc('?', stdout);
381 - } else if (*p == '\\') {
382 + } else if(*p == '\\') {
397 -void print_pkg_info(struct aurpkg_t *pkg) { /* {{{ */
399 +void print_pkg_info(struct aurpkg_t *pkg) /* {{{ */
405 printf(PKG_REPO " : %saur%s\n", colstr->repo, colstr->nc);
406 printf(NAME " : %s%s%s", colstr->pkg, pkg->name, colstr->nc);
407 - if ((ipkg = alpm_db_get_pkg(db_local, pkg->name))) {
408 + if((ipkg = alpm_db_get_pkg(db_local, pkg->name))) {
409 const char *instcolor;
410 - if (alpm_pkg_vercmp(pkg->ver, alpm_pkg_get_version(ipkg)) > 0) {
411 + if(alpm_pkg_vercmp(pkg->ver, alpm_pkg_get_version(ipkg)) > 0) {
412 instcolor = colstr->ood;
414 instcolor = colstr->utd;
416 printf(" %s[%sinstalled%s]%s", colstr->url, instcolor, colstr->url, colstr->nc);
419 + fputc('\n', stdout);
421 printf(VERSION " : %s%s%s\n",
422 pkg->ood ? colstr->ood : colstr->utd, pkg->ver, colstr->nc);
423 printf(URL " : %s%s%s\n", colstr->url, pkg->url, colstr->nc);
424 - printf(PKG_AURPAGE " : %s" AUR_PKG_URL_FORMAT "%s%s\n",
425 + printf(PKG_AURPAGE " : %s" AUR_PKG_URL_FORMAT "%d%s\n",
426 colstr->url, cfg.proto, pkg->id, colstr->nc);
428 print_extinfo_list(pkg->depends, PKG_DEPENDS, LIST_DELIM, 1);
429 @@ -1571,11 +1615,11 @@ void print_pkg_info(struct aurpkg_t *pkg) { /* {{{ */
430 print_extinfo_list(pkg->provides, PKG_PROVIDES, LIST_DELIM, 1);
431 print_extinfo_list(pkg->conflicts, PKG_CONFLICTS, LIST_DELIM, 1);
433 - if (pkg->optdepends) {
434 + if(pkg->optdepends) {
435 const alpm_list_t *i;
436 - printf(PKG_OPTDEPENDS " : %s\n", (const char*)alpm_list_getdata(pkg->optdepends));
437 - for (i = pkg->optdepends->next; i; i = alpm_list_next(i)) {
438 - printf("%-*s%s\n", INFO_INDENT, "", (const char*)alpm_list_getdata(i));
439 + printf(PKG_OPTDEPENDS " : %s\n", (const char*)pkg->optdepends->data);
440 + for(i = pkg->optdepends->next; i; i = alpm_list_next(i)) {
441 + printf("%-*s%s\n", INFO_INDENT, "", (const char*)i->data);
445 @@ -1583,13 +1627,13 @@ void print_pkg_info(struct aurpkg_t *pkg) { /* {{{ */
447 printf(PKG_CAT " : %s\n"
448 PKG_LICENSE " : %s\n"
449 - PKG_NUMVOTES " : %s\n"
450 + PKG_NUMVOTES " : %d\n"
451 PKG_OOD " : %s%s%s\n",
452 aur_cat[pkg->cat], pkg->lic, pkg->votes,
453 pkg->ood ? colstr->ood : colstr->utd,
454 pkg->ood ? "Yes" : "No", colstr->nc);
456 - printf(PKG_MAINT " : %s\n", pkg->maint);
457 + printf(PKG_MAINT " : %s\n", pkg->maint ? pkg->maint : "(orphan)");
459 ts = localtime(&pkg->firstsub);
460 strftime(datestring, 42, PKG_TIMEFMT, ts);
461 @@ -1604,17 +1648,18 @@ void print_pkg_info(struct aurpkg_t *pkg) { /* {{{ */
465 -void print_pkg_search(struct aurpkg_t *pkg) { /* {{{ */
467 +void print_pkg_search(struct aurpkg_t *pkg) /* {{{ */
470 printf("%s%s%s\n", colstr->pkg, pkg->name, colstr->nc);
473 - printf("%saur/%s%s%s %s%s%s%s (%s)", colstr->repo, colstr->nc, colstr->pkg,
474 + printf("%saur/%s%s%s %s%s%s%s (%d)", colstr->repo, colstr->nc, colstr->pkg,
475 pkg->name, pkg->ood ? colstr->ood : colstr->utd, pkg->ver,
476 NCFLAG(pkg->ood, " <!>"), colstr->nc, pkg->votes);
477 - if ((ipkg = alpm_db_get_pkg(db_local, pkg->name))) {
478 + if((ipkg = alpm_db_get_pkg(db_local, pkg->name))) {
479 const char *instcolor;
480 - if (alpm_pkg_vercmp(pkg->ver, alpm_pkg_get_version(ipkg)) > 0) {
481 + if(alpm_pkg_vercmp(pkg->ver, alpm_pkg_get_version(ipkg)) > 0) {
482 instcolor = colstr->ood;
484 instcolor = colstr->utd;
485 @@ -1623,7 +1668,7 @@ void print_pkg_search(struct aurpkg_t *pkg) { /* {{{ */
488 indentprint(pkg->desc, SRCH_INDENT);
490 + fputc('\n', stdout);
494 @@ -1948,9 +1993,8 @@ void *task_query(CURL *curl, void *arg) { /* {{{ */
498 - MALLOC(parse_struct, sizeof *parse_struct, return NULL);
499 - parse_struct->pkglist = NULL;
500 - parse_struct->json_depth = 0;
501 + CALLOC(parse_struct, 1, sizeof(struct yajl_parser_t), return NULL);
502 + CALLOC(parse_struct->aurpkg, 1, sizeof(struct aurpkg_t), return NULL);
503 yajl_hand = yajl_alloc(&callbacks, NULL, (void*)parse_struct);
505 curl = curl_init_easy_handle(curl);
506 @@ -2172,7 +2216,8 @@ void version() { /* {{{ */
510 -size_t yajl_parse_stream(void *ptr, size_t size, size_t nmemb, void *stream) { /* {{{ */
511 +size_t yajl_parse_stream(void *ptr, size_t size, size_t nmemb, void *stream) /* {{{ */
513 struct yajl_handle_t *hand;
514 size_t realsize = size * nmemb;