mirror of
https://github.com/ascii-boxes/boxes.git
synced 2024-12-04 22:11:07 +01:00
Extract tag query functionality into its own, new 'query' module #78
This commit is contained in:
parent
4d0dbcd59b
commit
82bc084bad
13
src/Makefile
13
src/Makefile
@ -28,11 +28,11 @@ GEN_HDR = parser.h boxes.h lex.yy.h
|
||||
GEN_SRC = parser.c lex.yy.c
|
||||
GEN_FILES = $(GEN_SRC) $(GEN_HDR)
|
||||
ORIG_HDRCL = boxes.in.h config.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) cmdline.h discovery.h generate.h input.h list.h parsecode.h parsing.h regulex.h remove.h \
|
||||
shape.h tools.h unicode.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) cmdline.h discovery.h generate.h input.h list.h parsecode.h parsing.h query.h regulex.h \
|
||||
remove.h shape.h tools.h unicode.h
|
||||
ORIG_GEN = lexer.l parser.y
|
||||
ORIG_NORM = boxes.c cmdline.c discovery.c generate.c input.c list.c parsecode.c parsing.c regulex.c remove.c shape.c \
|
||||
tools.c unicode.c
|
||||
ORIG_NORM = boxes.c cmdline.c discovery.c generate.c input.c list.c parsecode.c parsing.c query.c regulex.c remove.c \
|
||||
shape.c tools.c unicode.c
|
||||
ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM)
|
||||
ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR)
|
||||
|
||||
@ -95,10 +95,11 @@ generate.o: generate.c generate.h boxes.h shape.h tools.h unicode.h config.h |
|
||||
getopt.o: misc/getopt.c misc/getopt.h | check_dir
|
||||
input.o: input.c boxes.h input.h regulex.h tools.h unicode.h config.h | check_dir
|
||||
lex.yy.o: lex.yy.c parser.h boxes.h parsing.h tools.h shape.h config.h | check_dir
|
||||
list.o: list.c list.h boxes.h parsing.h tools.h config.h | check_dir
|
||||
parsecode.o: parsecode.c parser.h boxes.h tools.h lex.yy.h regulex.h unicode.h config.h | check_dir
|
||||
list.o: list.c list.h boxes.h parsing.h query.h tools.h config.h | check_dir
|
||||
parsecode.o: parsecode.c parser.h boxes.h tools.h lex.yy.h query.h regulex.h unicode.h config.h | check_dir
|
||||
parser.o: parser.c boxes.h lex.yy.h parser.h parsing.h tools.h shape.h discovery.h config.h | check_dir
|
||||
parsing.o: parsing.c parsing.h parser.h lex.yy.h boxes.h tools.h config.h | check_dir
|
||||
query.o: query.c query.h boxes.h list.h tools.h config.h | check_dir
|
||||
regulex.o: regulex.c regulex.h boxes.h tools.h unicode.h config.h | check_dir
|
||||
remove.o: remove.c remove.h boxes.h shape.h tools.h unicode.h config.h | check_dir
|
||||
shape.o: shape.c shape.h boxes.h tools.h config.h | check_dir
|
||||
|
66
src/boxes.c
66
src/boxes.c
@ -31,6 +31,7 @@
|
||||
#include "input.h"
|
||||
#include "list.h"
|
||||
#include "parsing.h"
|
||||
#include "query.h"
|
||||
#include "remove.h"
|
||||
#include "tools.h"
|
||||
#include "unicode.h"
|
||||
@ -158,71 +159,6 @@ static int build_design(design_t **adesigns, const char *cld)
|
||||
|
||||
|
||||
|
||||
int query_is_undoc()
|
||||
{
|
||||
return opt.query != NULL && strcmp(opt.query[0], QUERY_UNDOC) == 0 && opt.query[1] == NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int filter_by_tag(char **tags)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "filter_by_tag(");
|
||||
for (size_t tidx = 0; tags[tidx] != NULL; ++tidx) {
|
||||
fprintf(stderr, "%s%s", tidx > 0 ? ", " : "", tags[tidx]);
|
||||
}
|
||||
#endif
|
||||
|
||||
int result = array_contains0(opt.query, QUERY_ALL);
|
||||
if (opt.query != NULL) {
|
||||
for (size_t qidx = 0; opt.query[qidx] != NULL; ++qidx) {
|
||||
if (opt.query[qidx][0] == '+') {
|
||||
result = array_contains0(tags, opt.query[qidx] + 1);
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (opt.query[qidx][0] == '-') {
|
||||
if (array_contains0(tags, opt.query[qidx] + 1)) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (array_contains0(tags, opt.query[qidx])) {
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, ") -> %d\n", result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int query_by_tag()
|
||||
{
|
||||
design_t **list = sort_designs_by_name(); /* temp list for sorting */
|
||||
if (list == NULL) {
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < num_designs; ++i) {
|
||||
if (filter_by_tag(list[i]->tags)) {
|
||||
fprintf(opt.outfile, "%s%s", list[i]->name, opt.eol);
|
||||
for (size_t aidx = 0; list[i]->aliases[aidx] != NULL; ++aidx) {
|
||||
fprintf(opt.outfile, "%s (alias)%s", list[i]->aliases[aidx], opt.eol);
|
||||
}
|
||||
}
|
||||
}
|
||||
BFREE(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* _\|/_
|
||||
(o o)
|
||||
+----oOO-{_}-OOo------------------------------------------------------------+
|
||||
|
@ -134,13 +134,6 @@ typedef struct { /* Command line options: */
|
||||
|
||||
extern opt_t opt;
|
||||
|
||||
#define QUERY_ALL "(all)"
|
||||
#define QUERY_UNDOC "(undoc)"
|
||||
|
||||
/** Check if -q "(undoc)" was specified. */
|
||||
int query_is_undoc();
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t len; /* length of visible text in columns (visible character positions in a text terminal), which is the same as the length of the 'text' field */
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include "boxes.h"
|
||||
#include "discovery.h"
|
||||
#include "query.h"
|
||||
#include "tools.h"
|
||||
#include "cmdline.h"
|
||||
|
||||
@ -109,16 +110,6 @@ void usage_long(FILE *st)
|
||||
|
||||
|
||||
|
||||
static int validate_tag(char *tag)
|
||||
{
|
||||
if (strcmp(tag, QUERY_ALL) == 0 || strcmp(tag, QUERY_UNDOC) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return tag_is_valid(tag);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static opt_t *create_new_opt()
|
||||
{
|
||||
opt_t *result = (opt_t *) calloc(1, sizeof(opt_t));
|
||||
@ -427,70 +418,11 @@ static int padding(opt_t *result, char *optarg)
|
||||
* @param optarg the argument to `-q` on the command line
|
||||
* @returns 0 on success, anything else on error
|
||||
*/
|
||||
static int query_by_tag(opt_t *result, char *optarg)
|
||||
static int query(opt_t *result, char *optarg)
|
||||
{
|
||||
char **query = NULL;
|
||||
char *dup = strdup(optarg); /* required because strtok() modifies its input */
|
||||
|
||||
int contains_positive_element = 0;
|
||||
size_t num_expr = 0;
|
||||
for (char *q = strtok(dup, ","); q != NULL; q = strtok(NULL, ","))
|
||||
{
|
||||
char *trimmed = trimdup(q, q + strlen(q) - 1);
|
||||
if (strlen(trimmed) == 0) {
|
||||
BFREE(trimmed);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed[0] != '-') {
|
||||
contains_positive_element = 1;
|
||||
}
|
||||
|
||||
char *raw_tag = (trimmed[0] == '+' || trimmed[0] == '-') ? (trimmed + 1) : trimmed;
|
||||
if (!validate_tag(raw_tag)) {
|
||||
fprintf(stderr, "%s: not a tag -- %s\n", PROJECT, raw_tag);
|
||||
return 1;
|
||||
}
|
||||
if (query != NULL) {
|
||||
for (size_t i = 0; query[i] != NULL; ++i) {
|
||||
char *restag = (query[i][0] == '+' || query[i][0] == '-') ? (query[i] + 1) : query[i];
|
||||
if (strcasecmp(restag, raw_tag) == 0) {
|
||||
fprintf(stderr, "%s: duplicate query expression -- %s\n", PROJECT, trimmed);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++num_expr;
|
||||
query = (char **) realloc(query, (num_expr + 1) * sizeof(char *));
|
||||
if (query == NULL) {
|
||||
perror(PROJECT);
|
||||
break;
|
||||
}
|
||||
query[num_expr - 1] = trimmed;
|
||||
query[num_expr] = NULL;
|
||||
}
|
||||
BFREE(dup);
|
||||
|
||||
if (num_expr == 0) {
|
||||
fprintf(stderr, "%s: empty tag query -- %s\n", PROJECT, optarg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!contains_positive_element) {
|
||||
++num_expr;
|
||||
query = (char **) realloc(query, (num_expr + 1) * sizeof(char *));
|
||||
if (query == NULL) {
|
||||
perror(PROJECT);
|
||||
}
|
||||
else {
|
||||
query[num_expr - 1] = QUERY_ALL;
|
||||
query[num_expr] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char **query = parse_query(optarg);
|
||||
result->query = query;
|
||||
return 0;
|
||||
return query != NULL ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
@ -771,7 +703,7 @@ opt_t *process_commandline(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
if (query_by_tag(result, optarg) != 0) {
|
||||
if (query(result, optarg) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include "boxes.h"
|
||||
#include "parsing.h"
|
||||
#include "query.h"
|
||||
#include "tools.h"
|
||||
#include "list.h"
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "tools.h"
|
||||
#include "regulex.h"
|
||||
#include "unicode.h"
|
||||
#include "query.h"
|
||||
#include "parsecode.h"
|
||||
#include "parsing.h"
|
||||
#include "parser.h"
|
||||
|
189
src/query.c
Normal file
189
src/query.c
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License, version 2, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions related to querying the design list by tag.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "boxes.h"
|
||||
#include "list.h"
|
||||
#include "tools.h"
|
||||
#include "query.h"
|
||||
|
||||
|
||||
|
||||
#define QUERY_ALL "(all)"
|
||||
#define QUERY_UNDOC "(undoc)"
|
||||
|
||||
|
||||
|
||||
static int validate_tag(char *tag)
|
||||
{
|
||||
if (strcmp(tag, QUERY_ALL) == 0 || strcmp(tag, QUERY_UNDOC) == 0) {
|
||||
return 1;
|
||||
}
|
||||
return tag_is_valid(tag);
|
||||
}
|
||||
|
||||
|
||||
|
||||
char **parse_query(char *optarg)
|
||||
{
|
||||
/* CAUTION: This function cannot use `opt`, because it is involved in its construction. */
|
||||
|
||||
char **query = NULL;
|
||||
char *dup = strdup(optarg); /* required because strtok() modifies its input */
|
||||
|
||||
int contains_positive_element = 0;
|
||||
size_t num_expr = 0;
|
||||
for (char *q = strtok(dup, ","); q != NULL; q = strtok(NULL, ","))
|
||||
{
|
||||
char *trimmed = trimdup(q, q + strlen(q) - 1);
|
||||
if (strlen(trimmed) == 0) {
|
||||
BFREE(trimmed);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trimmed[0] != '-') {
|
||||
contains_positive_element = 1;
|
||||
}
|
||||
|
||||
char *raw_tag = (trimmed[0] == '+' || trimmed[0] == '-') ? (trimmed + 1) : trimmed;
|
||||
if (!validate_tag(raw_tag)) {
|
||||
fprintf(stderr, "%s: not a tag -- %s\n", PROJECT, raw_tag);
|
||||
BFREE(trimmed);
|
||||
BFREE(query);
|
||||
return NULL;
|
||||
}
|
||||
if (query != NULL) {
|
||||
for (size_t i = 0; query[i] != NULL; ++i) {
|
||||
char *restag = (query[i][0] == '+' || query[i][0] == '-') ? (query[i] + 1) : query[i];
|
||||
if (strcasecmp(restag, raw_tag) == 0) {
|
||||
fprintf(stderr, "%s: duplicate query expression -- %s\n", PROJECT, trimmed);
|
||||
BFREE(trimmed);
|
||||
BFREE(query);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++num_expr;
|
||||
query = (char **) realloc(query, (num_expr + 1) * sizeof(char *));
|
||||
if (query == NULL) {
|
||||
perror(PROJECT);
|
||||
break;
|
||||
}
|
||||
query[num_expr - 1] = trimmed;
|
||||
query[num_expr] = NULL;
|
||||
}
|
||||
BFREE(dup);
|
||||
|
||||
if (num_expr == 0) {
|
||||
fprintf(stderr, "%s: empty tag query -- %s\n", PROJECT, optarg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!contains_positive_element) {
|
||||
++num_expr;
|
||||
query = (char **) realloc(query, (num_expr + 1) * sizeof(char *));
|
||||
if (query == NULL) {
|
||||
perror(PROJECT);
|
||||
}
|
||||
else {
|
||||
query[num_expr - 1] = QUERY_ALL;
|
||||
query[num_expr] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int query_is_undoc()
|
||||
{
|
||||
return opt.query != NULL && strcmp(opt.query[0], QUERY_UNDOC) == 0 && opt.query[1] == NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int filter_by_tag(char **tags)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "filter_by_tag(");
|
||||
for (size_t tidx = 0; tags[tidx] != NULL; ++tidx) {
|
||||
fprintf(stderr, "%s%s", tidx > 0 ? ", " : "", tags[tidx]);
|
||||
}
|
||||
#endif
|
||||
|
||||
int result = array_contains0(opt.query, QUERY_ALL);
|
||||
if (opt.query != NULL) {
|
||||
for (size_t qidx = 0; opt.query[qidx] != NULL; ++qidx) {
|
||||
if (opt.query[qidx][0] == '+') {
|
||||
result = array_contains0(tags, opt.query[qidx] + 1);
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (opt.query[qidx][0] == '-') {
|
||||
if (array_contains0(tags, opt.query[qidx] + 1)) {
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (array_contains0(tags, opt.query[qidx])) {
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, ") -> %d\n", result);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int query_by_tag()
|
||||
{
|
||||
design_t **list = sort_designs_by_name(); /* temp list for sorting */
|
||||
if (list == NULL) {
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < num_designs; ++i) {
|
||||
if (filter_by_tag(list[i]->tags)) {
|
||||
fprintf(opt.outfile, "%s%s", list[i]->name, opt.eol);
|
||||
for (size_t aidx = 0; list[i]->aliases[aidx] != NULL; ++aidx) {
|
||||
fprintf(opt.outfile, "%s (alias)%s", list[i]->aliases[aidx], opt.eol);
|
||||
}
|
||||
}
|
||||
}
|
||||
BFREE(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set sw=4: */
|
53
src/query.h
Normal file
53
src/query.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2021 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License, version 2, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Functions related to querying the design list by tag.
|
||||
*/
|
||||
|
||||
#ifndef QUERY_H
|
||||
#define QUERY_H
|
||||
|
||||
|
||||
/**
|
||||
* Parse the tag query specified with the `-q` command line option.
|
||||
* @param optarg the argument to `-q` on the command line
|
||||
* @returns the parsed query which can be assigned to the global `opt` struct later, or `NULL` on error
|
||||
*/
|
||||
char **parse_query(char *optarg);
|
||||
|
||||
|
||||
/**
|
||||
* Check if -q "(undoc)" was specified.
|
||||
* @returns flag
|
||||
*/
|
||||
int query_is_undoc();
|
||||
|
||||
|
||||
/**
|
||||
* Perform the tag query based on the global design list and the query from the global `opt` struct.
|
||||
* @returns 0 if successful; anything else on error (then the program should exit)
|
||||
*/
|
||||
int query_by_tag();
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
Loading…
Reference in New Issue
Block a user