Untangle -l and -q options #23

Both are now used stand-alone for their respective purposes.
This commit is contained in:
Thomas Jensen 2021-04-06 21:22:18 +02:00
parent 76880f1c3c
commit 09d5ebcbb4
No known key found for this signature in database
GPG Key ID: A4ACEE270D0FB7DB
13 changed files with 107 additions and 88 deletions

View File

@ -7,7 +7,8 @@ boxes \- text mode box and comment drawing filter
.SH SYNOPSIS
.B boxes
[\-hlmrv] [\-a\ format] [\-d\ design] [\-f\ file] [\-i\ indent] [\-k\ bool]
[\-n\ encoding] [\-p\ pad] [\-s\ size] [\-t\ tabopts] [infile [outfile]]
[\-n\ encoding] [\-p\ pad] [\-q query] [\-s\ size] [\-t\ tabopts]
[infile [outfile]]
.SH DESCRIPTION
.I Boxes
is a text filter which can draw any kind of box around its input text. Box
@ -171,10 +172,7 @@ top part or a bottom part, the default is yes.
config file, along with a sample box and information about it's creator.
Also checks syntax of the entire config file. If used in connection with
.B \-d\fP,
displays detailed information about the specified design. If used in
connection with
.B \-q\fP,
displays only the design and alias names, but no further information.
displays detailed information about the specified design.
.\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
.TP 0.6i
.B \-m
@ -233,24 +231,26 @@ used.
.\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
.TP 0.6i
.B \-q \fIquery\fP
Query designs by tag. Can only be used in combination with
.B \-l\fP.
If used in other contexts, behavior is undefined.
.br
Query designs by tag. In contrast to
.B \-l\fP,
this will only print the matching design names. This option is normally used
stand-alone; if used in combination with other options, behavior is undefined.
The
.I query
argument is a comma-separated list of tags which can be present on a design
in order to match. A tag may optionally be prefixed with
.I \+
in order to require that a tag be present, or with
in order to require that it be present, or with
.I \-
in order to exclude designs which have that tag.
in order to exclude designs which have that tag. Each tag can only occur once
per query.
.br
Using this option alters the behavior of
.B \-l
so that only the design names are printed. This is intended for use by scripts.
Alias names are printed below their primary design name, and postfixed with
This option is intended for use by scripts. Alias names are printed below
their primary design name, and postfixed with
.I (alias)\fP.
.br
Example:
.I boxes -q programming,-comment
.\" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
.TP 0.6i
.B \-r

View File

@ -97,7 +97,7 @@ static void usage(FILE *st)
fprintf(st, " -m mend box, i.e. remove it and redraw it afterwards\n");
fprintf(st, " -n enc Character encoding of input and output [default: %s]\n", locale_charset());
fprintf(st, " -p fmt padding [default: none]\n");
fprintf(st, " -q qry in combination with -l, query design list by tag\n"); /* with (undoc) arg, trigger undocumented webui stuff */
fprintf(st, " -q qry query the list of designs by tag\n"); /* with "(undoc)" as query, trigger undocumented webui stuff instead */
fprintf(st, " -r remove box\n");
fprintf(st, " -s wxh box size (width w and/or height h)\n");
fprintf(st, " -t str tab stop distance and expansion [default: %de]\n", DEF_TABSTOP);
@ -948,16 +948,35 @@ static void print_tags(tagstats_t *tagstats, size_t num_tags)
static int list_styles()
/*
* Generate sorted listing of available box styles.
* Uses design name from BOX spec and sample picture plus author.
*
* RETURNS: != 0 on error (out of memory)
* == 0 on success
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/**
* Create a sorted shallow copy of the design array.
* @returns a new array, for which memory was allocated. All pointers in the array point to the original data.
* Returns `NULL` when out of memory.
*/
static design_t **sort_designs_by_name()
{
design_t **result = (design_t **) malloc(anz_designs * sizeof(design_t *));
if (result != NULL) {
for (int i = 0; i < anz_designs; ++i) {
result[i] = &(designs[i]);
}
qsort(result, anz_designs, sizeof(design_t *), style_sort);
}
else {
perror(PROJECT);
}
return result;
}
/**
* Generate sorted listing of available box styles.
* Uses design name from BOX spec and sample picture plus author.
* @returns != 0 on error (out of memory);
* == 0 on success
*/
static int list_styles()
{
int i;
@ -1136,62 +1155,40 @@ static int list_styles()
else {
design_t **list; /* temp list for sorting */
list = (design_t **) calloc(anz_designs, sizeof(design_t *));
if (list == NULL) {
perror(PROJECT);
return 1;
}
for (i = 0; i < anz_designs; ++i) {
list[i] = &(designs[i]);
}
qsort(list, anz_designs, sizeof(design_t *), style_sort);
tagstats_t *tagstats = NULL;
size_t num_tags = 0;
if (opt.query == NULL) {
print_design_list_header();
design_t **list = sort_designs_by_name(); /* temp list for sorting */
if (list == NULL) {
return 1;
}
print_design_list_header();
for (i = 0; i < anz_designs; ++i) {
if (opt.query != NULL) {
if (filter_by_tag(list[i]->tags)) {
fprintf(opt.outfile, "%s\n", list[i]->name);
for (size_t aidx = 0; list[i]->aliases[aidx] != NULL; ++aidx) {
fprintf(opt.outfile, "%s (alias)\n", list[i]->aliases[aidx]);
}
}
char *all_names = names(list[i]);
if (list[i]->author && list[i]->designer && strcmp(list[i]->author, list[i]->designer) != 0) {
fprintf(opt.outfile, "%s\n%s, coded by %s:\n\n%s\n\n", all_names,
list[i]->designer, list[i]->author, list[i]->sample);
}
else if (list[i]->designer) {
fprintf(opt.outfile, "%s\n%s:\n\n%s\n\n", all_names, list[i]->designer, list[i]->sample);
}
else if (list[i]->author) {
fprintf(opt.outfile, "%s\nunknown artist, coded by %s:\n\n%s\n\n", all_names,
list[i]->author, list[i]->sample);
}
else {
char *all_names = names(list[i]);
if (list[i]->author && list[i]->designer && strcmp(list[i]->author, list[i]->designer) != 0) {
fprintf(opt.outfile, "%s\n%s, coded by %s:\n\n%s\n\n", all_names,
list[i]->designer, list[i]->author, list[i]->sample);
}
else if (list[i]->designer) {
fprintf(opt.outfile, "%s\n%s:\n\n%s\n\n", all_names, list[i]->designer, list[i]->sample);
}
else if (list[i]->author) {
fprintf(opt.outfile, "%s\nunknown artist, coded by %s:\n\n%s\n\n", all_names,
list[i]->author, list[i]->sample);
}
else {
fprintf(opt.outfile, "%s:\n\n%s\n\n", all_names, list[i]->sample);
}
BFREE(all_names);
fprintf(opt.outfile, "%s:\n\n%s\n\n", all_names, list[i]->sample);
}
BFREE(all_names);
for (size_t tidx = 0; list[i]->tags[tidx] != NULL; ++tidx) {
count_tag(list[i]->tags[tidx], &tagstats, &num_tags);
}
for (size_t tidx = 0; list[i]->tags[tidx] != NULL; ++tidx) {
count_tag(list[i]->tags[tidx], &tagstats, &num_tags);
}
}
BFREE(list);
if (opt.query == NULL) {
print_tags(tagstats, num_tags);
BFREE(tagstats);
}
print_tags(tagstats, num_tags);
BFREE(tagstats);
}
return 0;
@ -1199,6 +1196,26 @@ static int list_styles()
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 < anz_designs; ++i) {
if (filter_by_tag(list[i]->tags)) {
fprintf(opt.outfile, "%s\n", list[i]->name);
for (size_t aidx = 0; list[i]->aliases[aidx] != NULL; ++aidx) {
fprintf(opt.outfile, "%s (alias)\n", list[i]->aliases[aidx]);
}
}
}
BFREE(list);
return 0;
}
static int get_indent(const line_t *lines, const size_t lines_size)
/*
* Determine indentation of given lines in spaces.
@ -1626,6 +1643,14 @@ int main(int argc, char *argv[])
exit(rc);
}
/*
* If "-q" option was given, print results of tag query and exit.
*/
if (opt.query != NULL && opt.query[0] != NULL && !query_is_undoc()) {
rc = query_by_tag();
exit(rc);
}
/*
* Adjust box size and indentmode to command line specification
* Increase box width/height by width/height of empty sides in order

View File

@ -348,7 +348,7 @@ static int design_needed(pass_to_bison *bison_args)
return design_has_name(&(curdes), (char *) opt.design);
}
else {
if (opt.r || opt.l) {
if (opt.r || opt.l || (opt.query != NULL && !query_is_undoc())) {
return 1;
}
if (bison_args->design_idx == 0) {
@ -748,9 +748,9 @@ int action_add_design(pass_to_bison *bison_args, char *design_primary_name, char
/*
* Check if we need to continue parsing. If not, return.
* The condition here must correspond to design_needed() in parsecode.c.
* The condition here must correspond to the function design_needed().
*/
if (opt.design_choice_by_user || (!opt.r && !opt.l)) {
if (opt.design_choice_by_user || (!opt.r && !opt.l && (opt.query == NULL || query_is_undoc()))) {
bison_args->num_designs = bison_args->design_idx + 1;
return RC_ACCEPT;
}

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q tag1,tag2
-f 14x_tag_query.cfg -q tag1,tag2
:INPUT
:OUTPUT-FILTER
:EXPECTED

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q +tag1,tag2
-f 14x_tag_query.cfg -q +tag1,tag2
:INPUT
:OUTPUT-FILTER
:EXPECTED

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q +tag1,+tag3
-f 14x_tag_query.cfg -q +tag1,+tag3
:INPUT
:OUTPUT-FILTER
:EXPECTED

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q -tag1
-f 14x_tag_query.cfg -q -tag1
:INPUT
:OUTPUT-FILTER
:EXPECTED

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q -tag1,-tag2
-f 14x_tag_query.cfg -q -tag1,-tag2
:INPUT
:OUTPUT-FILTER
:EXPECTED

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q (all)
-f 14x_tag_query.cfg -q (all)
:INPUT
:OUTPUT-FILTER
:EXPECTED

View File

@ -1,5 +1,5 @@
:ARGS
-f 146_tag_query.cfg -l -q INVALID
-f 146_tag_query.cfg -q INVALID
:INPUT
:OUTPUT-FILTER
:EXPECTED-ERROR 1

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q -tag1,+tag1
-f 14x_tag_query.cfg -q -tag1,+tag1
:INPUT
:OUTPUT-FILTER
:EXPECTED-ERROR 1

View File

@ -1,5 +1,5 @@
:ARGS
-f 14x_tag_query.cfg -l -q -tag1,tag1
-f 14x_tag_query.cfg -q -tag1,tag1
:INPUT
:OUTPUT-FILTER
:EXPECTED-ERROR 1

View File

@ -1,6 +0,0 @@
:ARGS
-f 14x_tag_query.cfg -l -q non-existent
:INPUT
:OUTPUT-FILTER
:EXPECTED
:EOF