/* This file is part of cfpeek Copyright (C) 2011, 2012, 2015 Sergey Poznyakoff Cfpeek is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Cfpeek is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cfpeek. If not, see . */ #include "cfpeek.h" #include "grecs-locus.h" int file_index; int flags; int quiet_option; int reduce_option; int sort_option; unsigned max_matches; char *script_file; char *script_expr; char *script_init_expr; char *script_done_expr; #define MODE_GLOB 0 #define MODE_LITERAL 1 int mode = MODE_GLOB; enum locate_cmd { locate_undefined, locate_up, locate_down, locate_parent, locate_child, locate_sibling }; struct locate_instr { enum locate_cmd cmd; union { char *s; int n; } v; }; static struct grecs_list *locate_list; static struct locate_instr * new_locate_instr() { struct locate_instr *p = grecs_zalloc(sizeof(*p)); if (!locate_list) locate_list = grecs_list_create(); grecs_list_append(locate_list, p); return p; } static struct grecs_node * run_locate(struct grecs_node *node) { int i; struct grecs_list_entry *ep; if (!locate_list) return node; for (ep = locate_list->head; ep; ep = ep->next) { struct locate_instr *instr = ep->data; switch (instr->cmd) { case locate_undefined: grecs_error(NULL, 0, "%s:%d: internal error: " "locate_instr not initialized", __FILE__, __LINE__); exit(EX_SOFTWARE); case locate_up: for (i = 0; i < instr->v.n && node; i++) node = node->up; break; case locate_down: for (i = 0; i < instr->v.n && node; i++) node = node->down; break; case locate_parent: while (node && strcmp(node->ident, instr->v.s)) node = node->up; break; case locate_child: node = grecs_find_node(node->down, instr->v.s); break; case locate_sibling: node = grecs_find_node(node->up->down, instr->v.s); } } return node; } #include "cmdline.h" static void _print_diag(grecs_locus_t const *locus, int err, int errcode, const char *msg) { fflush(stdout); if (!locus) fprintf(stderr, "%s: ", program_name); if (locus) { YY_LOCATION_PRINT(stderr, *locus); fprintf(stderr, ": "); } if (!err) fprintf(stderr, "warning: "); fprintf(stderr, "%s", msg); if (errcode) fprintf(stderr, ": %s", strerror(errno)); fputc('\n', stderr); } static int node_ident_cmp(struct grecs_node const *a, struct grecs_node const *b) { return strcmp(a->ident, b->ident); } struct literal_match_buf { const char *pattern; struct grecs_node *node; }; static struct grecs_node * literal_first_node(struct grecs_node *tree, const char *pattern, void **pptr) { struct grecs_node *node = grecs_find_node(tree, pattern); if (node) { struct literal_match_buf *buf = grecs_malloc(sizeof(*buf)); buf->pattern = pattern; buf->node = node; *pptr = buf; } return node; } static struct grecs_node * literal_next_node(void *ptr) { struct literal_match_buf *buf = ptr; if (buf->node) buf->node = grecs_find_node(buf->node->next, buf->pattern); return buf->node; } static void literal_free(void *ptr) { grecs_free(ptr); } static struct grecs_node * glob_first_node(struct grecs_node *tree, const char *pattern, void **pptr) { grecs_match_buf_t match_buf; struct grecs_node *node = grecs_match_first(tree, pattern, &match_buf); *pptr = match_buf; return node; } static struct grecs_node * glob_next_node(void *ptr) { grecs_match_buf_t match_buf = ptr; return grecs_match_next(match_buf); } static void glob_free(void *ptr) { grecs_match_buf_t match_buf = ptr; grecs_match_buf_free(match_buf); } struct cfpeek_engine { struct grecs_node *(*first_node)(struct grecs_node *, const char *, void **); struct grecs_node *(*next_node)(void *); void (*free_buf)(void *); }; struct cfpeek_engine cfpeek_engine[] = { { glob_first_node, glob_next_node, glob_free }, { literal_first_node, literal_next_node, literal_free }, }; static void cfpeek_print(struct grecs_node *node) { if (script_run(node)) { grecs_print_node(node, flags, stdout); fputc('\n', stdout); } } static void print_node(struct grecs_node *node) { node = run_locate(node); if (!node) return; cfpeek_print(node); } static enum grecs_tree_recurse_res eval_rec(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) { if (op == grecs_tree_recurse_set) script_run(node); return grecs_tree_recurse_ok; } static void scan_tree(struct grecs_node *tree) { if (script_file || script_expr) { grecs_tree_recurse(tree, eval_rec, NULL); } else cfpeek_print(tree); } int main(int argc, char **argv) { struct grecs_node *tree; struct cfpeek_engine *cfp; int rc = EX_OK; grecs_print_diag_fun = _print_diag; parse_options(argc, argv); argc -= file_index; argv += file_index; if (argc < 1) { grecs_error(NULL, 0, "not enough arguments"); exit(EX_USAGE); } tree = grecs_parse(argv[0]); if (!tree) exit(EX_PARSE); if (cmdline_tree) { grecs_tree_join(tree, cmdline_tree); grecs_tree_free(cmdline_tree); } if (reduce_option) grecs_tree_reduce(tree, NULL, 0); if (sort_option) grecs_tree_sort(tree, node_ident_cmp); if (argc < 2) { flags |= GRECS_NODE_FLAG_DESCEND; scan_tree(tree); script_done(); exit(EX_OK); } cfp = &cfpeek_engine[mode]; while (--argc) { void *match_buf = NULL; char *arg = *++argv; struct grecs_node *node = cfp->first_node(tree, arg, &match_buf); if (!node) { if (!quiet_option) grecs_error(NULL, 0, "%s: not found", arg); rc = EX_NOTFOUND; } else if (quiet_option <= 1) { int i = 0; do { print_node(node); if (max_matches && ++i == max_matches) break; } while (node = cfp->next_node(match_buf)); } cfp->free_buf(match_buf); } script_done(); exit(rc); }