From c16a1cea13c70e9c40a8db82d561e71bd04f404f Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 16 Nov 2014 16:51:30 -0500 Subject: Reorg a bit, introduce a control struct --- .gitignore | 5 + .ycm_extra_conf.py | 85 +++++++++++ Makefile | 9 +- conf.c | 182 ++++++++++++++++++++++ conf.h | 15 ++ expac.c | 439 ++++++++++++++++------------------------------------- expac.h | 23 +++ util.h | 14 ++ 8 files changed, 464 insertions(+), 308 deletions(-) create mode 100644 .gitignore create mode 100644 .ycm_extra_conf.py create mode 100644 conf.c create mode 100644 conf.h create mode 100644 expac.h create mode 100644 util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ebba7c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +.*.swp +expac +expac.1 +.ycm_extra_conf.pyc diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 0000000..6ba1cca --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,85 @@ +import os +import ycm_core +from clang_helpers import PrepareClangFlags + +# Set this to the absolute path to the folder (NOT the file!) containing the +# compile_commands.json file to use that instead of 'flags'. See here for +# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html +# Most projects will NOT need to set this to anything; you can just change the +# 'flags' list of compilation flags. Notice that YCM itself uses that approach. +compilation_database_folder = '' + +# These are the compilation flags that will be used in case there's no +# compilation database set. +flags = [ +'-Wall', +'-Wextra', +'-Werror', +'-Wno-long-long', +'-Wno-variadic-macros', +'-fexceptions', +'-DNDEBUG', +'-D_GNU_SOURCE', +'-DUSE_CLANG_COMPLETER', +'-std=c99', +'-DVERSION="1"', +] + +if compilation_database_folder: + database = ycm_core.CompilationDatabase( compilation_database_folder ) +else: + database = None + + +def DirectoryOfThisScript(): + return os.path.dirname( os.path.abspath( __file__ ) ) + + +def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): + if not working_directory: + return flags + new_flags = [] + make_next_absolute = False + path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith( '/' ): + new_flag = os.path.join( working_directory, flag ) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith( path_flag ): + path = flag[ len( path_flag ): ] + new_flag = path_flag + os.path.join( working_directory, path ) + break + + if new_flag: + new_flags.append( new_flag ) + return new_flags + + +def FlagsForFile( filename ): + if database: + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = database.GetCompilationInfoForFile( filename ) + final_flags = PrepareClangFlags( + MakeRelativePathsInFlagsAbsolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_ ), + filename ) + + else: + relative_to = DirectoryOfThisScript() + final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) + + return { + 'flags': final_flags, + 'do_cache': True + } diff --git a/Makefile b/Makefile index 85b47a9..d585e4f 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,13 @@ LDLIBS = -lalpm DISTFILES = expac.c README.pod +expac_SOURCES = \ + expac.c \ + conf.c conf.h \ + util.h + +expac: $(expac_SOURCES) + all: expac doc doc: expac.1 @@ -30,6 +37,6 @@ dist: clean rm -rf expac-$(VERSION) clean: - $(RM) expac.o expac expac.1 + $(RM) *.o expac expac.1 .PHONY: all clean dist doc install doc diff --git a/conf.c b/conf.c new file mode 100644 index 0000000..5aedc6e --- /dev/null +++ b/conf.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include + +#include "conf.h" +#include "util.h" + +static size_t strtrim(char *str) { + char *left = str, *right; + + if (!str || *str == '\0') { + return 0; + } + + while (isspace((unsigned char)*left)) { + left++; + } + if (left != str) { + memmove(str, left, (strlen(left) + 1)); + left = str; + } + + if (*str == '\0') { + return 0; + } + + right = strchr(str, '\0') - 1; + while (isspace((unsigned char)*right)) { + right--; + } + *++right = '\0'; + + return right - left; +} + +int is_section(const char *s, int n) { + return s[0] == '[' && s[n-1] == ']'; +} + +static int config_add_repo(config_t *config, char *reponame) { + /* first time setup */ + if (config->repos == NULL) { + config->repos = calloc(10, sizeof(char*)); + if (config->repos == NULL) { + return -ENOMEM; + } + + config->size = 0; + config->capacity = 10; + } + + /* grow when needed */ + if (config->size == config->capacity) { + void *ptr; + + ptr = realloc(config->repos, config->capacity * 2.5 * sizeof(char*)); + if (ptr == NULL) { + return -ENOMEM; + } + + config->repos = ptr; + } + + config->repos[config->size] = strdup(reponame); + ++config->size; + + return 0; +} + +static int parse_one_file(config_t *config, const char *filename, char **section); + +static int parse_include(config_t *config, const char *include, char **section) { + _cleanup_(globfreep) glob_t globbuf = {}; + + if (glob(include, GLOB_NOCHECK, NULL, &globbuf) != 0) { + fprintf(stderr, "warning: globbing failed on '%s': out of memory\n", + include); + return -ENOMEM; + } + + for (size_t i = 0; i < globbuf.gl_pathc; ++i) { + int r; + r = parse_one_file(config, globbuf.gl_pathv[i], section); + if (r < 0) + return r; + } + + return 0; +} + +static char *split_keyval(char *line, const char *sep) { + strsep(&line, sep); + return line; +} + +static int parse_one_file(config_t *config, const char *filename, char **section) { + _cleanup_(fclosep) FILE *fp = NULL; + _cleanup_free_ char *line = NULL; + size_t n = 0; + int in_options = 0; + + if (*section) + in_options = strcmp(*section, "options") == 0; + + fp = fopen(filename, "r"); + if (fp == NULL) + return -errno; + + for (;;) { + ssize_t len; + + errno = 0; + len = getline(&line, &n, fp); + if (len < 0) { + if (errno != 0) + return -errno; + + /* EOF */ + break; + } + + len = strtrim(line); + if (len == 0 || line[0] == '#') + continue; + + if (is_section(line, len)) { + free(*section); + *section = strndup(&line[1], len - 2); + if (*section == NULL) + return -ENOMEM; + + in_options = strcmp(*section, "options") == 0; + if (!in_options) { + int r; + + r = config_add_repo(config, *section); + if (r < 0) + return r; + + } + continue; + } + + if (in_options && memchr(line, '=', len)) { + char *val; + + val = split_keyval(line, "="); + strtrim(line); + + if (strcmp(line, "Include") == 0) { + int k; + + strtrim(val); + + k = parse_include(config, val, section); + if (k < 0) + return k; + } + } + } + + return 0; +} + +void config_reset(config_t *config) { + if (config == NULL) + return; + + for (int i = 0; i < config->size; ++i) + free(config->repos[i]); + + free(config->repos); +} + +int config_parse(config_t *config, const char *filename) { + _cleanup_free_ char *section = NULL; + + return parse_one_file(config, filename, §ion); +} + +/* vim: set et ts=2 sw=2: */ diff --git a/conf.h b/conf.h new file mode 100644 index 0000000..1ce6a17 --- /dev/null +++ b/conf.h @@ -0,0 +1,15 @@ +#ifndef _CONF_H +#define _CONF_H + +typedef struct config_t { + char **repos; + int size; + int capacity; +} config_t; + +int config_parse(config_t *config, const char *filename); +void config_reset(config_t *config); + +#endif /* _CONF_H */ + +/* vim: set et ts=2 sw=2: */ diff --git a/expac.c b/expac.c index b519d4d..b6f7b0e 100644 --- a/expac.c +++ b/expac.c @@ -36,6 +36,10 @@ #include #include +#include "expac.h" +#include "conf.h" +#include "util.h" + #define DEFAULT_DELIM "\n" #define DEFAULT_LISTDELIM " " #define DEFAULT_TIMEFMT "%c" @@ -50,208 +54,23 @@ static char const digits[] = "0123456789"; static char const printf_flags[] = "'-+ #0I"; alpm_db_t *db_local = NULL; -alpm_list_t *dblist = NULL; alpm_list_t *targets = NULL; bool opt_readone = false; bool opt_verbose = false; bool opt_search = false; -bool opt_local = false; bool opt_groups = false; bool opt_localpkg = false; char opt_humansize = 'B'; +SearchCorpus opt_corpus = SEARCH_LOCAL; const char *opt_format = NULL; const char *opt_timefmt = DEFAULT_TIMEFMT; const char *opt_listdelim = DEFAULT_LISTDELIM; const char *opt_delim = DEFAULT_DELIM; +const char *opt_config_file = "/etc/pacman.conf"; int opt_pkgcounter = 0; typedef const char *(*extractfn)(void*); -typedef struct config_t { - char **repos; - int size; - int capacity; -} config_t; - -static inline void freep(void *p) { free(*(void **)p); } -static inline void fclosep(FILE **p) { if (*p) fclose(*p); } -static inline void globfreep(glob_t *p) { globfree(p); } -#define _cleanup_(x) __attribute__((cleanup(x))) -#define _cleanup_free_ _cleanup_(freep) - -static size_t strtrim(char *str) { - char *left = str, *right; - - if (!str || *str == '\0') { - return 0; - } - - while (isspace((unsigned char)*left)) { - left++; - } - if (left != str) { - memmove(str, left, (strlen(left) + 1)); - left = str; - } - - if (*str == '\0') { - return 0; - } - - right = strchr(str, '\0') - 1; - while (isspace((unsigned char)*right)) { - right--; - } - *++right = '\0'; - - return right - left; -} - -int is_section(const char *s, int n) { - return s[0] == '[' && s[n-1] == ']'; -} - -static int config_add_repo(config_t *config, char *reponame) { - /* first time setup */ - if (config->repos == NULL) { - config->repos = calloc(10, sizeof(char*)); - if (config->repos == NULL) { - return -ENOMEM; - } - - config->size = 0; - config->capacity = 10; - } - - /* grow when needed */ - if (config->size == config->capacity) { - void *ptr; - - ptr = realloc(config->repos, config->capacity * 2.5 * sizeof(char*)); - if (ptr == NULL) { - return -ENOMEM; - } - - config->repos = ptr; - } - - config->repos[config->size] = strdup(reponame); - ++config->size; - - return 0; -} - -void config_reset(config_t *config) { - if (config == NULL) - return; - - for (int i = 0; i < config->size; ++i) - free(config->repos[i]); - - free(config->repos); -} - -static int parse_one_file(config_t *config, const char *filename, char **section); - -static int parse_include(config_t *config, const char *include, char **section) { - _cleanup_(globfreep) glob_t globbuf = {}; - - if (glob(include, GLOB_NOCHECK, NULL, &globbuf) != 0) { - fprintf(stderr, "warning: globbing failed on '%s': out of memory\n", - include); - return -ENOMEM; - } - - for (size_t i = 0; i < globbuf.gl_pathc; ++i) { - int r; - r = parse_one_file(config, globbuf.gl_pathv[i], section); - if (r < 0) - return r; - } - - return 0; -} - -static char *split_keyval(char *line, const char *sep) { - strsep(&line, sep); - return line; -} - -static int parse_one_file(config_t *config, const char *filename, char **section) { - _cleanup_(fclosep) FILE *fp = NULL; - _cleanup_free_ char *line = NULL; - size_t n = 0; - int in_options = 0; - - if (*section) - in_options = strcmp(*section, "options") == 0; - - fp = fopen(filename, "r"); - if (fp == NULL) - return -errno; - - for (;;) { - ssize_t len; - - errno = 0; - len = getline(&line, &n, fp); - if (len < 0) { - if (errno != 0) - return -errno; - - /* EOF */ - break; - } - - len = strtrim(line); - if (len == 0 || line[0] == '#') - continue; - - if (is_section(line, len)) { - free(*section); - *section = strndup(&line[1], len - 2); - if (*section == NULL) - return -ENOMEM; - - in_options = strcmp(*section, "options") == 0; - if (!in_options) { - int r; - - r = config_add_repo(config, *section); - if (r < 0) - return r; - - } - continue; - } - - if (in_options && memchr(line, '=', len)) { - char *val; - - val = split_keyval(line, "="); - strtrim(line); - - if (strcmp(line, "Include") == 0) { - int k; - - strtrim(val); - - k = parse_include(config, val, section); - if (k < 0) - return k; - } - } - } - - return 0; -} - -static int config_parse(config_t *config, const char *filename) { - _cleanup_free_ char *section = NULL; - - return parse_one_file(config, filename, §ion); -} - static const char *alpm_backup_get_name(alpm_backup_t *bkup) { return bkup->name; } @@ -303,35 +122,6 @@ static char *format_optdep(alpm_depend_t *optdep) { return out; } -static alpm_handle_t *alpm_init(void) { - alpm_handle_t *alpm = NULL; - enum _alpm_errno_t alpm_errno = 0; - config_t config = { NULL, 0, 0 }; - int r; - - alpm = alpm_initialize("/", "/var/lib/pacman", &alpm_errno); - if (!alpm) { - alpm_strerror(alpm_errno); - return NULL; - } - - db_local = alpm_get_localdb(alpm); - - r = config_parse(&config, "/etc/pacman.conf"); - if (r < 0) { - fprintf(stderr, "error: failed to parse config: %s\n", strerror(-r)); - return NULL; - } - - for (int i = 0; i < config.size; ++i) { - alpm_register_syncdb(alpm, config.repos[i], 0); - } - - config_reset(&config); - - return alpm; -} - static const char *alpm_dep_get_name(void *dep) { return ((alpm_depend_t*)dep)->name; } @@ -356,8 +146,7 @@ static void usage(void) { "For more details see expac(1).\n"); } -static int parse_options(int argc, char *argv[], alpm_handle_t *alpm) { - int opt, option_index = 0; +static int parse_options(int argc, char *argv[]) { const char *i; static struct option opts[] = { @@ -376,22 +165,19 @@ static int parse_options(int argc, char *argv[], alpm_handle_t *alpm) { {0, 0, 0, 0} }; - while (-1 != (opt = getopt_long(argc, argv, "1l:d:gH:hf:pQSst:v", opts, &option_index))) { + for (;;) { + int opt; + + opt = getopt_long(argc, argv, "1l:d:gH:hf:pQSst:v", opts, NULL); + if (opt < 0) + break; + switch (opt) { case 'S': - if (dblist) { - fprintf(stderr, "error: can only select one repo option (use -h for help)\n"); - return 1; - } - dblist = alpm_list_copy(alpm_get_syncdbs(alpm)); + opt_corpus = SEARCH_SYNC; break; case 'Q': - if (dblist) { - fprintf(stderr, "error: can only select one repo option (use -h for help)\n"); - return 1; - } - dblist = alpm_list_add(dblist, db_local); - opt_local = true; + opt_corpus = SEARCH_LOCAL; break; case '1': opt_readone = true; @@ -406,13 +192,13 @@ static int parse_options(int argc, char *argv[], alpm_handle_t *alpm) { opt_listdelim = optarg; break; case 'H': - for(i = SIZE_TOKENS; *i; i++) { - if(*i == *optarg) { + for (i = SIZE_TOKENS; *i; i++) { + if (*i == *optarg) { opt_humansize = *optarg; break; } } - if(*i == '\0') { + if (*i == '\0') { fprintf(stderr, "error: invalid SI size formatter: %c\n", *optarg); return 1; } @@ -421,7 +207,7 @@ static int parse_options(int argc, char *argv[], alpm_handle_t *alpm) { usage(); return 1; case 'p': - opt_localpkg = true; + opt_corpus = SEARCH_FILE; break; case 's': opt_search = true; @@ -440,9 +226,9 @@ static int parse_options(int argc, char *argv[], alpm_handle_t *alpm) { } } - if (optind < argc) { + if (optind < argc) opt_format = argv[optind++]; - } else { + else { fprintf(stderr, "error: missing format string (use -h for help)\n"); return 1; } @@ -588,7 +374,7 @@ static bool backup_file_is_modified(const alpm_backup_t *backup_file) { static alpm_list_t *get_modified_files(alpm_pkg_t *pkg) { alpm_list_t *i, *modified_files = NULL; - for(i = alpm_pkg_get_backup(pkg); i; i = alpm_list_next(i)) { + for(i = alpm_pkg_get_backup(pkg); i; i = i->next) { const alpm_backup_t *backup = i->data; if(backup->hash && backup_file_is_modified(backup)) { modified_files = alpm_list_add(modified_files, backup->name); @@ -809,126 +595,165 @@ static alpm_list_t *search_groups(alpm_list_t *dbs, alpm_list_t *groupnames) { return packages; } -static alpm_list_t *resolve_pkg(alpm_list_t *targets) { +static alpm_list_t *resolve_pkg(alpm_list_t *dblist, alpm_list_t *targets) { char *pkgname, *reponame; alpm_list_t *t, *r, *ret = NULL; - if (targets == NULL) { + if (targets == NULL) return all_packages(dblist); - } else if (opt_search) { + else if (opt_search) return search_packages(dblist, targets); - } else if (opt_groups) { + else if (opt_groups) return search_groups(dblist, targets); - } /* resolve each target individually from the repo pool */ - for (t = targets; t; t = alpm_list_next(t)) { + for (t = targets; t; t = t->next) { alpm_pkg_t *pkg = NULL; int found = 0; pkgname = reponame = t->data; - if (strchr(pkgname, '/')) { + if (strchr(pkgname, '/')) strsep(&pkgname, "/"); - } else { + else reponame = NULL; - } - for (r = dblist; r; r = alpm_list_next(r)) { + for (r = dblist; r; r = r->next) { alpm_db_t *repo = r->data; - if (reponame && strcmp(reponame, alpm_db_get_name(repo)) != 0) { + if (reponame && strcmp(reponame, alpm_db_get_name(repo)) != 0) continue; - } pkg = alpm_db_get_pkg(repo, pkgname); - if (pkg == NULL) { + if (pkg == NULL) continue; - } found = 1; ret = alpm_list_add(ret, pkg); - if (opt_readone) { + if (opt_readone) break; - } } - if (!found && opt_verbose) { + if (!found && opt_verbose) fprintf(stderr, "error: package `%s' not found\n", pkgname); - } } return ret; } -static alpm_list_t *gather_packages(alpm_handle_t *alpm, alpm_list_t *targets) { - alpm_list_t *results = NULL; +void expac_free(Expac *expac) { + if (expac == NULL) + return; - if (opt_localpkg) { - alpm_list_t *i; + alpm_release(expac->alpm); +} - /* load each target as a package */ - for (i = targets; i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg; - int err; +int expac_new(Expac **expac, int argc, char **argv) { + Expac *e; + enum _alpm_errno_t alpm_errno = 0; + config_t config = { NULL, 0, 0 }; + int r; - err = alpm_pkg_load(alpm, i->data, 0, 0, &pkg); - if (err) { - fprintf(stderr, "error: %s: %s\n", (const char*)i->data, - alpm_strerror(alpm_errno(alpm))); - continue; - } - results = alpm_list_add(results, pkg); + r = parse_options(argc, argv); + if (r < 0) + return r; + + e = calloc(1, sizeof(*e)); + if (e == NULL) + return -ENOMEM; + + r = config_parse(&config, opt_config_file); + if (r < 0) + return r; + + e->alpm = alpm_initialize("/", "/var/lib/pacman", &alpm_errno); + if (!e->alpm) + return -alpm_errno; + + e->db_local = alpm_get_localdb(e->alpm); + + for (int i = 0; i < config.size; ++i) + alpm_register_syncdb(e->alpm, config.repos[i], 0); + + config_reset(&config); + + *expac = e; + + return 0; +} + +int expac_search_files(Expac *expac, alpm_list_t *targets, alpm_list_t **results) { + alpm_list_t *i; + + /* load each target as a package */ + for (i = targets; i; i = alpm_list_next(i)) { + alpm_pkg_t *pkg; + int err; + + err = alpm_pkg_load(expac->alpm, i->data, 0, 0, &pkg); + if (err) { + fprintf(stderr, "error: %s: %s\n", (const char*)i->data, + alpm_strerror(alpm_errno(expac->alpm))); + continue; } - } else { - results = resolve_pkg(targets); + *results = alpm_list_add(*results, pkg); } - return results; + return 0; } -int main(int argc, char *argv[]) { - int ret = 1; - alpm_handle_t *alpm; - alpm_list_t *results = NULL, *i; +int expac_search_local(Expac *expac, alpm_list_t *targets, alpm_list_t **results) { + alpm_list_t *dblist; - alpm = alpm_init(); - if (!alpm) { - return ret; - } + dblist = alpm_list_add(NULL, alpm_get_localdb(expac->alpm)); - ret = parse_options(argc, argv, alpm); - if (ret != 0) { - goto finish; - } + *results = resolve_pkg(dblist, targets); - /* ensure sane defaults */ - if (!dblist && !opt_localpkg) { - opt_local = true; - dblist = alpm_list_add(dblist, db_local); - } + alpm_list_free(dblist); - results = gather_packages(alpm, targets); - if (results == NULL) { - ret = 1; - goto finish; - } + return 0; +} - for (i = results; i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg = i->data; - ret += print_pkg(pkg, opt_format); - } - ret = !!ret; /* clamp to zero/one */ +int expac_search_sync(Expac *expac, alpm_list_t *targets, alpm_list_t **results) { + *results = resolve_pkg(alpm_get_syncdbs(expac->alpm), targets); + return 0; +} - if(opt_localpkg) { - alpm_list_free_inner(results, (alpm_list_fn_free)alpm_pkg_free); +int expac_search(Expac *expac, alpm_list_t *targets, alpm_list_t **results) { + switch (opt_corpus) { + case SEARCH_LOCAL: + return expac_search_local(expac, targets, results); + case SEARCH_SYNC: + return expac_search_sync(expac, targets, results); + case SEARCH_FILE: + return expac_search_files(expac, targets, results); } + + return 0; +} + +int main(int argc, char *argv[]) { + alpm_list_t *results = NULL; + Expac *expac; + int r; + + r = expac_new(&expac, argc, argv); + if (r < 0) + return 1; + + r = expac_search(expac, targets, &results); + if (r < 0) + return 1; + + if (alpm_list_count(results) == 0) + return 1; + + for (alpm_list_t *i = results; i; i = i->next) + print_pkg(i->data, opt_format); + alpm_list_free(results); + expac_free(expac); -finish: - alpm_list_free(dblist); - alpm_list_free(targets); - alpm_release(alpm); - return ret; + return r; } /* vim: set et ts=2 sw=2: */ diff --git a/expac.h b/expac.h new file mode 100644 index 0000000..29536b2 --- /dev/null +++ b/expac.h @@ -0,0 +1,23 @@ +#ifndef _EXPAC_H +#define _EXPAC_H + +#include + +typedef enum SearchCorpus { + SEARCH_LOCAL, + SEARCH_SYNC, + SEARCH_FILE, +} SearchCorpus; + +typedef struct Expac { + alpm_handle_t *alpm; + alpm_db_t *db_local; + + SearchCorpus search_type; +} Expac; + +int expac_new(Expac **expac, int argc, char **argv); + +#endif /* _EXPAC_H */ + +/* vim: set et ts=2 sw=2: */ diff --git a/util.h b/util.h new file mode 100644 index 0000000..6d50426 --- /dev/null +++ b/util.h @@ -0,0 +1,14 @@ +#ifndef _UTIL_H +#define _UTIL_H + +#include +#include +#include + +static inline void freep(void *p) { free(*(void **)p); } +static inline void fclosep(FILE **p) { if (*p) fclose(*p); } +static inline void globfreep(glob_t *p) { globfree(p); } +#define _cleanup_(x) __attribute__((cleanup(x))) +#define _cleanup_free_ _cleanup_(freep) + +#endif /* _UTIL_H */ -- cgit v1.2.3-54-g00ecf