#include <sys/types.h>
#include <ctype.h>
#include <err.h>
#include <getopt.h>
#include <inttypes.h>
#include <pkg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pkgcli.h"
static struct query_flags accepted_rquery_flags[] = {
{ 'd', "nov", 1, PKG_LOAD_DEPS },
{ 'r', "nov", 1, PKG_LOAD_RDEPS },
{ 'C', "", 1, PKG_LOAD_CATEGORIES },
{ 'O', "kvdD", 1, PKG_LOAD_OPTIONS },
{ 'L', "", 1, PKG_LOAD_LICENSES },
{ 'B', "", 1, PKG_LOAD_SHLIBS_REQUIRED },
{ 'b', "", 1, PKG_LOAD_SHLIBS_PROVIDED },
{ 'A', "tv", 1, PKG_LOAD_ANNOTATIONS },
{ '?', "drCOLBbA", 1, PKG_LOAD_BASIC },
{ '#', "drCOLBbA", 1, PKG_LOAD_BASIC },
{ 's', "hb", 0, PKG_LOAD_BASIC },
{ 'n', "", 0, PKG_LOAD_BASIC },
{ 'e', "", 0, PKG_LOAD_BASIC },
{ 'v', "", 0, PKG_LOAD_BASIC },
{ 'o', "", 0, PKG_LOAD_BASIC },
{ 'R', "", 0, PKG_LOAD_BASIC },
{ 'p', "", 0, PKG_LOAD_BASIC },
{ 'm', "", 0, PKG_LOAD_BASIC },
{ 'c', "", 0, PKG_LOAD_BASIC },
{ 'w', "", 0, PKG_LOAD_BASIC },
{ 'l', "", 0, PKG_LOAD_BASIC },
{ 'q', "", 0, PKG_LOAD_BASIC },
{ 'M', "", 0, PKG_LOAD_BASIC }
};
void
usage_rquery(void)
{
fprintf(stderr, "Usage: pkg rquery [-r reponame] [-I|<query-format>] <pkg-name>\n");
fprintf(stderr, " pkg rquery [-a] [-r reponame] [-I|<query-format>]\n");
fprintf(stderr, " pkg rquery -e <evaluation> [-r reponame] <query-format>\n");
fprintf(stderr, " pkg rquery [-Cgix] [-r reponame] [-I|<query-format>] <pattern> <...>\n\n");
fprintf(stderr, "For more information see 'pkg help rquery.'\n");
}
static void
print_index(struct pkg *pkg, const char *portsdir)
{
pkg_printf(
"%n-%v|"
"%S/%o|"
"%p|"
"%c|"
"%S/%o/pkg-descr|"
"%m|"
"%C%{%Cn%| %}|"
"|"
"%d%{%dn-%dv%| %}|"
"%w|"
"|"
"|"
"\n",
pkg, pkg, portsdir, pkg, pkg, pkg, portsdir, pkg, pkg, pkg, pkg,
pkg);
}
int
exec_rquery(int argc, char **argv)
{
struct pkgdb *db = NULL;
struct pkgdb_it *it = NULL;
struct pkg *pkg = NULL;
char *pkgname = NULL;
int query_flags = PKG_LOAD_BASIC;
match_t match = MATCH_EXACT;
int ch;
int ret = EPKG_OK;
int retcode = EXIT_SUCCESS;
int i;
char multiline = 0;
char *condition = NULL;
const char *condition_sql = NULL;
const char *portsdir;
xstring *sqlcond = NULL;
const unsigned int q_flags_len = NELEM(accepted_rquery_flags);
bool onematched = false;
bool old_quiet;
bool index_output = false;
c_charv_t reponames = vec_init();
struct option longopts[] = {
{ "all", no_argument, NULL, 'a' },
{ "case-sensitive", no_argument, NULL, 'C' },
{ "evaluate", required_argument, NULL, 'e' },
{ "glob", no_argument, NULL, 'g' },
{ "case-insensitive", no_argument, NULL, 'i' },
{ "index-line", no_argument, NULL, 'I' },
{ "repository", required_argument, NULL, 'r' },
{ "no-repo-update", no_argument, NULL, 'U' },
{ "regex", no_argument, NULL, 'x' },
{ NULL, 0, NULL, 0 },
};
portsdir = pkg_object_string(pkg_config_get("PORTSDIR"));
while ((ch = getopt_long(argc, argv, "+aCgiIxe:r:U", longopts, NULL)) != -1) {
switch (ch) {
case 'a':
match = MATCH_ALL;
break;
case 'C':
pkgdb_set_case_sensitivity(true);
break;
case 'e':
condition = optarg;
break;
case 'g':
match = MATCH_GLOB;
break;
case 'i':
pkgdb_set_case_sensitivity(false);
break;
case 'I':
index_output = true;
break;
case 'r':
vec_push(&reponames, optarg);
break;
case 'U':
auto_update = false;
break;
case 'x':
match = MATCH_REGEX;
break;
default:
usage_rquery();
return (EXIT_FAILURE);
}
}
argc -= optind;
argv += optind;
if (argc == 0 && !index_output) {
usage_rquery();
return (EXIT_FAILURE);
}
if (!index_output) {
if (argc == 1 && match == MATCH_EXACT) {
match = MATCH_ALL;
} else if (((argc == 1) ^ (match == MATCH_ALL )) && condition == NULL) {
usage_rquery();
return (EXIT_FAILURE);
}
} else {
if (argc == 0)
match = MATCH_ALL;
}
if (!index_output && analyse_query_string(argv[0], accepted_rquery_flags, q_flags_len, &query_flags, &multiline) != EPKG_OK)
return (EXIT_FAILURE);
if (condition != NULL) {
sqlcond = xstring_new();
if (format_sql_condition(condition, sqlcond, true) != EPKG_OK) {
xstring_free(sqlcond);
return (EXIT_FAILURE);
}
}
ret = pkgdb_access2(PKGDB_MODE_READ, PKGDB_DB_REPO, &reponames);
if (ret == EPKG_ENOACCESS) {
warnx("Insufficient privileges to query the package database");
xstring_free(sqlcond);
return (EXIT_FAILURE);
} else if (ret != EPKG_OK) {
xstring_free(sqlcond);
return (EXIT_FAILURE);
}
old_quiet = quiet;
quiet = true;
if (auto_update && (ret = pkgcli_update(false, false, &reponames)) != EPKG_OK) {
xstring_free(sqlcond);
return (ret);
}
quiet = old_quiet;
ret = pkgdb_open_all2(&db, PKGDB_REMOTE, &reponames);
if (ret != EPKG_OK) {
xstring_free(sqlcond);
return (EXIT_FAILURE);
}
pkg_drop_privileges();
if (index_output)
query_flags = PKG_LOAD_BASIC|PKG_LOAD_CATEGORIES|PKG_LOAD_DEPS;
if (sqlcond) {
fflush(sqlcond->fp);
condition_sql = sqlcond->buf;
}
if (match == MATCH_ALL) {
if ((it = pkgdb_repo_query_cond2(db, condition_sql, NULL, match, &reponames)) == NULL) {
xstring_free(sqlcond);
return (EXIT_FAILURE);
}
while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
if (index_output)
print_index(pkg, portsdir);
else
print_query(pkg, argv[0], multiline);
}
if (ret != EPKG_END)
retcode = EXIT_FAILURE;
pkgdb_it_free(it);
} else {
for (i = (index_output ? 0 : 1); i < argc; i++) {
pkgname = argv[i];
if ((it = pkgdb_repo_query_cond2(db, condition_sql, pkgname, match, &reponames)) == NULL) {
xstring_free(sqlcond);
return (EXIT_FAILURE);
}
while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) {
onematched = true;
if (index_output)
print_index(pkg, portsdir);
else
print_query(pkg, argv[0], multiline);
}
if (ret != EPKG_END) {
retcode = EXIT_FAILURE;
break;
}
pkgdb_it_free(it);
}
if (!onematched && retcode == EXIT_SUCCESS)
retcode = EXIT_FAILURE;
}
xstring_free(sqlcond);
pkg_free(pkg);
pkgdb_close(db);
return (retcode);
}