mirror of
https://github.com/ascii-boxes/boxes.git
synced 2024-12-04 22:11:07 +01:00
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:
parent
aab643acbc
commit
27adf5b6ba
94
src/boxes.c
94
src/boxes.c
@ -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 {
|
||||
|
@ -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) */
|
||||
|
@ -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",
|
||||
|
32
src/parser.y
32
src/parser.y
@ -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;
|
||||
|
33
src/tools.c
33
src/tools.c
@ -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: */
|
||||
|
18
src/tools.h
18
src/tools.h
@ -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: */
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-ac -q -s 12
|
||||
-ac -q (undoc) -s 12
|
||||
:INPUT
|
||||
foo
|
||||
barf
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-ar -q -s 12
|
||||
-ar -q (undoc) -s 12
|
||||
:INPUT
|
||||
foo
|
||||
barf
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-q -s 12
|
||||
-q (undoc) -s 12
|
||||
:INPUT
|
||||
foo
|
||||
barf
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-ac -q -s 18x5 -p h3
|
||||
-ac -q (undoc) -s 18x5 -p h3
|
||||
:INPUT
|
||||
foo
|
||||
barf
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-q -t 8k
|
||||
-q (undoc) -t 8k
|
||||
:INPUT
|
||||
foo
|
||||
barf
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-q -s 12
|
||||
-q (undoc) -s 12
|
||||
:INPUT
|
||||
f
|
||||
fo
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-q -s 12 -al
|
||||
-q (undoc) -s 12 -al
|
||||
:INPUT
|
||||
f
|
||||
fo
|
||||
|
@ -1,5 +1,5 @@
|
||||
:ARGS
|
||||
-q -d right
|
||||
-q (undoc) -d right
|
||||
:INPUT
|
||||
foo
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user