Add argument to -q option for tag queries #23

-q is no longer undocumented,
but can officially be used in combination with -l
This commit is contained in:
Thomas Jensen 2021-04-02 22:12:21 +02:00
parent aab643acbc
commit 27adf5b6ba
No known key found for this signature in database
GPG Key ID: A4ACEE270D0FB7DB
18 changed files with 150 additions and 55 deletions

View File

@ -90,7 +90,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 modify command for needs of the web UI (undocumented)\n"); */
fprintf(st, " -q qry in combination with -l, query design list by tag\n"); /* with (undoc) arg, trigger undocumented webui stuff */
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);
@ -128,6 +128,55 @@ static void usage_long(FILE *st)
static int validate_tag(char *tag)
{
if (strcmp(tag, "(all)") == 0 || strcmp(tag, "(undoc)") == 0) {
return 1;
}
return tag_is_valid(tag);
}
static char **parse_tag_query(char *optarg)
{
char **result = NULL;
char *dup = strdup(optarg); /* required because strtok() modifies its input */
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] == '+' || trimmed[0] == '-') {
if (!validate_tag(trimmed + 1)) {
fprintf(stderr, "%s: not a tag -- %s\n", PROJECT, trimmed + 1);
return NULL;
}
} else if (!validate_tag(trimmed)) {
fprintf(stderr, "%s: not a tag -- %s\n", PROJECT, trimmed);
return NULL;
}
++num_expr;
result = (char **) realloc(result, (num_expr + 1) * sizeof(char *));
if (result == NULL) {
perror(PROJECT);
break;
}
result[num_expr - 1] = trimmed;
result[num_expr] = NULL;
}
BFREE(dup);
return result;
}
static int process_commandline(int argc, char *argv[])
/*
* Process command line options.
@ -157,6 +206,7 @@ static int process_commandline(int argc, char *argv[])
opt.tabexp = 'e';
opt.killblank = -1;
opt.encoding = NULL;
opt.query = NULL;
for (idummy = 0; idummy < ANZ_SIDES; ++idummy) {
opt.padding[idummy] = -1;
}
@ -173,7 +223,7 @@ static int process_commandline(int argc, char *argv[])
* Parse Command Line
*/
do {
oc = getopt(argc, argv, "a:c:d:f:hi:k:lmn:p:qrs:t:v");
oc = getopt(argc, argv, "a:c:d:f:hi:k:lmn:p:q:rs:t:v");
switch (oc) {
@ -416,9 +466,13 @@ static int process_commandline(int argc, char *argv[])
case 'q':
/*
* Activate special behavior for web UI (undocumented)
* Record the argument of the '-q' option. Combined with '-l', this is a tag query,
* else it activates undocumented special behavior used by the web UI.
*/
opt.q = 1;
opt.query = parse_tag_query(optarg);
if (opt.query == NULL) {
return 1;
}
break;
case 'r':
@ -584,7 +638,15 @@ static int process_commandline(int argc, char *argv[])
fprintf (stderr, "- Line justification: \'%c\'\n", opt.justify? opt.justify: '?');
fprintf (stderr, "- Kill blank lines: %d\n", opt.killblank);
fprintf (stderr, "- Remove box: %d\n", opt.r);
fprintf (stderr, "- Special handling for Web UI: %d\n", opt.q);
fprintf (stderr, "- Tag Query / Special handling for Web UI: ");
if (opt.query != NULL) {
for (size_t qidx = 0; opt.query[qidx] != NULL; ++qidx) {
fprintf(stderr, "%s%s", qidx > 0 ? ", " : "", opt.query[qidx]);
}
} else {
fprintf (stderr, "(none)");
}
fprintf (stderr, "\n");
fprintf (stderr, "- Mend box: %d\n", opt.mend);
fprintf (stderr, "- Design Definition W shape: %s\n", opt.cld? opt.cld: "n/a");
#endif
@ -765,6 +827,14 @@ static char *names(design_t *design)
static int filter_by_tag(char **tags)
{
// TODO
return 1; // TODO or 0 if the tags don't match
}
static int list_styles()
/*
* Generate sorted listing of available box styles.
@ -927,7 +997,7 @@ static int list_styles()
/*
* Display all shapes
*/
if (opt.q) {
if (opt.query != NULL) {
fprintf(opt.outfile, "Sample:\n%s\n", d->sample);
}
else {
@ -966,14 +1036,16 @@ static int list_styles()
}
qsort(list, anz_designs, sizeof(design_t *), style_sort);
if (!opt.q) {
if (opt.query == NULL) {
print_design_list_header();
}
for (i = 0; i < anz_designs; ++i) {
if (opt.q) {
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]);
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]);
}
}
}
else {

View File

@ -123,7 +123,7 @@ typedef struct { /* Command line options: */
int l; /** list available designs */
char *f; /** the string specified as argument to -f ; config file path */
int mend; /** 1 if -m is given, 2 in 2nd loop */
int q; /** special handling of web UI needs */
char **query; /** parsed tag query expression passed in via -q; also, special handling of web UI needs */
int r; /** remove box from input */
int tabstop; /** tab stop distance */
char tabexp; /** tab expansion mode (for leading tabs) */

View File

@ -1034,7 +1034,7 @@ int output_box(const sentry_t *thebox)
}
/* add info line for web ui if requested with -q */
if (opt.q) {
if (opt.query != NULL) {
fprintf(opt.outfile, "%d ", (int) (thebox[BTOP].height + vfill1_save - skip_start));
for (j = 0; j < input.anz_lines; j++) {
fprintf(opt.outfile, "%d%s",

View File

@ -416,18 +416,6 @@ static int design_name_exists(pass_to_bison *bison_args, char *name)
static int tag_is_valid(char *tag)
{
const size_t len = strlen(tag);
return len > 0
&& strspn(tag, "abcdefghijklmnopqrstuvwxyz-0123456789") == len
&& strchr("abcdefghijklmnopqrstuvwxyz", tag[0]) != NULL
&& tag[len - 1] != '-'
&& strstr(tag, "--") == NULL;
}
static int tag_add(pass_to_bison *bison_args, char *tag)
{
int rc = 0;
@ -463,22 +451,6 @@ static char *tag_next_comma(char *s)
static char *tag_trim(char *s, char *e)
{
if (s > e || (s == e && *s == '\0')) {
return strdup("");
}
while (s <= e && (*s == ' ' || *s == '\t')) {
++s;
}
while (e > s && (*e == ' ' || *e == '\t')) {
--e;
}
return strndup(s, e - s + 1);
}
static int tag_split_add(pass_to_bison *bison_args, char *tag)
{
int rc = 0;
@ -486,7 +458,7 @@ static int tag_split_add(pass_to_bison *bison_args, char *tag)
char *c = NULL;
do {
c = tag_next_comma(s);
char *single_tag = tag_trim(s, c - 1);
char *single_tag = trimdup(s, c - 1);
int rc_add = tag_add(bison_args, single_tag);
if (rc_add != 0) {
rc = rc_add;
@ -511,7 +483,7 @@ static int tag_record(pass_to_bison *bison_args, char *tag)
rc = tag_split_add(bison_args, tag);
}
else {
char *trimmed = tag_trim(tag, tag + strlen(tag) - 1);
char *trimmed = trimdup(tag, tag + strlen(tag) - 1);
rc = tag_add(bison_args, trimmed);
}
return rc;

View File

@ -682,4 +682,37 @@ size_t array_count0(char **array)
}
char *trimdup(char *s, char *e)
{
if (s > e || (s == e && *s == '\0')) {
return strdup("");
}
while (s <= e && (*s == ' ' || *s == '\t')) {
++s;
}
while (e > s && (*e == ' ' || *e == '\t')) {
--e;
}
return strndup(s, e - s + 1);
}
int tag_is_valid(char *tag)
{
if (tag == NULL) {
return 0;
}
const size_t len = strlen(tag);
return len > 0
&& strspn(tag, "abcdefghijklmnopqrstuvwxyz-0123456789") == len
&& strchr("abcdefghijklmnopqrstuvwxyz", tag[0]) != NULL
&& tag[len - 1] != '-'
&& strstr(tag, "--") == NULL;
}
/*EOF*/ /* vim: set sw=4: */

View File

@ -97,6 +97,24 @@ int array_contains0(char **array, const char *s);
*/
size_t array_count0(char **array);
/**
* Trim leading and trailing whitespace from a string and return the result in a new string, for which memory is
* allocated. `s` and `e` may point into some other string, which will not be modified. `e` should be greater than `s`.
* @param s pointer to the first character of the string
* @param e pointer to the last character of the string (NOT the character AFTER the last)
* @returns a new string, which may be the empty string if the input was invalid or consisted only of whitespace
*/
char *trimdup(char *s, char *e);
/**
* Determine if the given string is a valid tag. Valid tags are lower-case alphanumeric strings which may have
* intermixed, single hyphens. A valid tag starts with a letter. Hyphens may also not appear as last character.
* @param tag a potential tag
* @return flag indicating validity
*/
int tag_is_valid(char *tag);
#endif
/*EOF*/ /* vim: set cindent sw=4: */

View File

@ -1,5 +1,5 @@
:ARGS
-ac -q -s 12
-ac -q (undoc) -s 12
:INPUT
foo
barf

View File

@ -1,5 +1,5 @@
:ARGS
-ar -q -s 12
-ar -q (undoc) -s 12
:INPUT
foo
barf

View File

@ -1,5 +1,5 @@
:ARGS
-q -s 12
-q (undoc) -s 12
:INPUT
foo
barf

View File

@ -1,5 +1,5 @@
:ARGS
-ac -q -s 18x5 -p h3
-ac -q (undoc) -s 18x5 -p h3
:INPUT
foo
barf

View File

@ -1,5 +1,5 @@
:ARGS
-ac -q -s 18 -p a3 -i box
-ac -q (undoc) -s 18 -p a3 -i box
:INPUT
foo
barf

View File

@ -1,5 +1,5 @@
:ARGS
-ac -q -p a3 -d diamonds -i text
-ac -q (undoc) -p a3 -d diamonds -i text
:INPUT
foo
barf

View File

@ -1,5 +1,5 @@
:ARGS
-q -t 8k
-q (undoc) -t 8k
:INPUT
foo
barf

View File

@ -1,5 +1,5 @@
:ARGS
-q -s 12
-q (undoc) -s 12
:INPUT
f
fo

View File

@ -1,5 +1,5 @@
:ARGS
-q -s 12 -al
-q (undoc) -s 12 -al
:INPUT
f
fo

View File

@ -1,5 +1,5 @@
:ARGS
-q -d right
-q (undoc) -d right
:INPUT
foo

View File

@ -20,7 +20,7 @@ Reversion Rules: none
Minimum Box Dimensions: 3 x 3 (width x height)
Default Padding: left 1, right 1
Default Killblank: no
Tags: (none)
Tags: none
Elastic Shapes: N, E, S, W
Defined Shapes: E: "X"
W: "X"

View File

@ -20,7 +20,7 @@ Reversion Rules: none
Minimum Box Dimensions: 5 x 3 (width x height)
Default Padding: left 1, right 1
Default Killblank: no
Tags: (none)
Tags: none
Elastic Shapes: N, E, S, W
Defined Shapes: E: "X3"
W: "X3"