/* SPDX-License-Identifier: GPL-3.0-only */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "err.h" /** Compute the minimum of \a x and \a y. */ #define MIN(x, y) ({ \ typeof(x) _min1 = (x); \ typeof(y) _min2 = (y); \ (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) /** Compute the maximum of \a x and \a y. */ #define MAX(x, y) ({ \ typeof(x) _max1 = (x); \ typeof(y) _max2 = (y); \ (void) (&_max1 == &_max2); \ _max1 < _max2 ? _max2 : _max1; }) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /* util.c */ extern int loglevel_arg_val; enum loglevels {LOGLEVELS, NUM_LOGLEVELS}; void tf_log(int ll, const char* fmt,...); #define DEBUG_LOG(f,...) tf_log(LL_DEBUG, "%s: " f, __FUNCTION__, ## __VA_ARGS__) #define INFO_LOG(f,...) tf_log(LL_INFO, "%s: " f, __FUNCTION__, ## __VA_ARGS__) #define NOTICE_LOG(f,...) tf_log(LL_NOTICE, "%s: " f, __FUNCTION__, ## __VA_ARGS__) #define WARNING_LOG(f,...) tf_log(LL_WARNING, "%s: " f, __FUNCTION__, ## __VA_ARGS__) #define ERROR_LOG(f,...) tf_log(LL_ERROR, "%s: " f, __FUNCTION__, ## __VA_ARGS__) #define CRIT_LOG(f,...) tf_log(LL_CRIT, "%s: " f, __FUNCTION__, ## __VA_ARGS__) #define EMERG_LOG(f,...) tf_log(LL_EMERG, "%s: " f, __FUNCTION__, ## __VA_ARGS__) int atoi64(const char *str, int64_t *value); unsigned xvasprintf(char **result, const char *fmt, va_list ap); unsigned xasprintf(char **result, const char *fmt, ...); void *xrealloc(void *p, size_t size); void *xmalloc(size_t size); void *xcalloc(size_t size); char *xstrdup(const char *str); char *get_homedir(void); int xregcomp(regex_t *preg, const char *regex, int cflags); void mmap_file(const char *path, struct iovec *iov); int fd2buf(int fd, struct iovec *result); struct regfile_iter; /* opaque */ void regfile_iter_new(const char *dirname, struct regfile_iter **result); bool regfile_iter_map(const struct regfile_iter *iter, struct iovec *result); const char *regfile_iter_basename(const struct regfile_iter *iter); const struct stat *regfile_iter_stat(const struct regfile_iter *iter); void regfile_iter_next(struct regfile_iter *iter); void regfile_iter_free(struct regfile_iter *iter); /* tfortune.c */ struct epi_properties; /* opaque */ unsigned epi_len(const struct epi_properties *props); bool epi_has_tag(const char *tag, const struct epi_properties *props); char *epi_text(const struct epi_properties *props); /* version.c */ const char *tf_version(void); /* tag expression parser (ast.c, txp.lex, txp.y) */ /* Opaque, only known to ast.c. Passed to the generated txp_yyparse(). */ struct txp_context; int txp_init(const struct iovec *definition, struct txp_context **result, char **errmsg); bool txp_eval_ast(const struct txp_context *ctx, const struct epi_properties *props); void txp_free(struct txp_context *ctx); /* non-public API of the tag expression parser */ /* * Since we use a reentrant lexer, all functions generated by flex(1) * receive an additional argument of this type. */ typedef void *txp_yyscan_t; /* Parsed regex pattern. */ struct txp_re_pattern { regex_t preg; /* Pre-compiled regex. */ unsigned flags; /* Subset of the cflags described in regex(3). */ }; /* * The possible values of a node in the abstract syntax tree (AST). * * Constant semantic values (string literals, numeric constants and regex * patterns which are part of the tag expression) are determined during * txp_init() while values which depend on the epigram (tags, number of lines, * etc.) are determined during txp_eval_row(). * * This union, and the txp_ast_node structure below are used extensively in * txp.y. However, both need to be public because the lexer must be able to * create AST nodes for the constant semantic values. */ union txp_semantic_value { bool boolval; /* Comparators, =~ and =|. */ char *strval; /* String literals (e.g., argument of tag()) */ int64_t intval; /* Constants, num_lines, etc. */ struct txp_re_pattern re_pattern; /* Right-hand side operand of =~. */ }; /* * A node is either interior or a leaf node. Interior nodes have at least one * child while leaf nodes have a semantic value and no children. * * Examples: (a) STRING_LITERAL has a semantic value (the unescaped string * literal) and no children, (b) NEG (unary minus) has no semantic value but * one child (the numeric expression that is to be negated), (c) LESS_OR_EQUAL * has no semantic value and two children (the two numeric expressions being * compared). */ struct txp_ast_node { /* Corresponds to a token type, for example LESS_OR_EQUAL. */ int id; union { /* Pointers to the child nodes (interior nodes only). */ struct txp_ast_node **children; /* Leaf nodes only. */ union txp_semantic_value sv; }; /* * The number of children is implicitly given by the id, but we include * it here to avoid having to maintain a lookup table. The AST is * usually small, so we can afford to waste a byte per node. */ uint8_t num_children; }; /* Called from both the lexer and the parser. */ __attribute__ ((format (printf, 3, 4))) void txp_parse_error(int line, struct txp_context *ctx, const char *fmt, ...); /* Helper functions for the lexer. */ unsigned parse_quoted_string(const char *src, const char quote_chars[2], char **result); int txp_parse_regex_pattern(const char *src, struct txp_re_pattern *result); struct txp_ast_node *ast_node_new_unary(int id, struct txp_ast_node *child); struct txp_ast_node *ast_node_new_binary(int id, struct txp_ast_node *left, struct txp_ast_node *right); struct txp_ast_node *txp_new_ast_leaf_node(int id); /* linhash.c */ struct linhash_item { const char *key; void *object; }; typedef int linhash_comparator(const struct linhash_item **a, const struct linhash_item **b); struct linhash_table; struct linhash_iterator; struct linhash_table *linhash_new(uint32_t order); int linhash_insert(struct linhash_item *item, struct linhash_table *t, void ***object); struct linhash_item *linhash_lookup(const char *key, const struct linhash_table *t); void *linhash_remove(const char *key, struct linhash_table *t); void linhash_free(struct linhash_table *t); struct linhash_iterator *linhash_iterator_new(struct linhash_table *t, linhash_comparator *comp, bool reverse); struct linhash_item *linhash_iterator_item(const struct linhash_iterator *iter); void linhash_iterator_next(struct linhash_iterator *iter); void linhash_iterator_free(struct linhash_iterator *iter); char *linhash_statistics(const struct linhash_table *t); uint32_t linhash_num_items(const struct linhash_table *t);