mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-08-11 23:59:33 +02:00
Extract list_designs functionality into its own, new 'list' module #78
This commit is contained in:
@ -28,9 +28,9 @@ GEN_HDR = parser.h boxes.h lex.yy.h
|
|||||||
GEN_SRC = parser.c lex.yy.c
|
GEN_SRC = parser.c lex.yy.c
|
||||||
GEN_FILES = $(GEN_SRC) $(GEN_HDR)
|
GEN_FILES = $(GEN_SRC) $(GEN_HDR)
|
||||||
ORIG_HDRCL = boxes.in.h config.h
|
ORIG_HDRCL = boxes.in.h config.h
|
||||||
ORIG_HDR = $(ORIG_HDRCL) cmdline.h discovery.h generate.h lexer.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 list.h parsecode.h parsing.h regulex.h remove.h shape.h tools.h unicode.h
|
||||||
ORIG_GEN = lexer.l parser.y
|
ORIG_GEN = lexer.l parser.y
|
||||||
ORIG_NORM = boxes.c cmdline.c discovery.c generate.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 list.c parsecode.c parsing.c regulex.c remove.c shape.c tools.c unicode.c
|
||||||
ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM)
|
ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM)
|
||||||
ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR)
|
ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR)
|
||||||
|
|
||||||
@ -86,12 +86,13 @@ parser.c parser.h: parser.y lex.yy.h | check_dir
|
|||||||
lex.yy.c lex.yy.h: lexer.l | check_dir
|
lex.yy.c lex.yy.h: lexer.l | check_dir
|
||||||
$(LEX) --header-file=lex.yy.h $<
|
$(LEX) --header-file=lex.yy.h $<
|
||||||
|
|
||||||
boxes.o: boxes.c boxes.h discovery.h regulex.h shape.h tools.h unicode.h generate.h remove.h config.h | check_dir
|
boxes.o: boxes.c boxes.h cmdline.h discovery.h regulex.h shape.h tools.h unicode.h generate.h list.h remove.h config.h | check_dir
|
||||||
cmdline.o: cmdline.c cmdline.h boxes.h tools.h config.h | check_dir
|
cmdline.o: cmdline.c cmdline.h boxes.h tools.h config.h | check_dir
|
||||||
discovery.o: discovery.c discovery.h boxes.h tools.h config.h | check_dir
|
discovery.o: discovery.c discovery.h boxes.h tools.h config.h | check_dir
|
||||||
generate.o: generate.c generate.h boxes.h shape.h tools.h unicode.h config.h | check_dir
|
generate.o: generate.c generate.h boxes.h shape.h tools.h unicode.h config.h | check_dir
|
||||||
getopt.o: misc/getopt.c misc/getopt.h | check_dir
|
getopt.o: misc/getopt.c misc/getopt.h | check_dir
|
||||||
lex.yy.o: lex.yy.c parser.h boxes.h parsing.h tools.h shape.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
|
parsecode.o: parsecode.c parser.h boxes.h tools.h lex.yy.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
|
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
|
parsing.o: parsing.c parsing.h parser.h lex.yy.h boxes.h tools.h config.h | check_dir
|
||||||
|
376
src/boxes.c
376
src/boxes.c
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include "boxes.h"
|
#include "boxes.h"
|
||||||
#include "cmdline.h"
|
#include "cmdline.h"
|
||||||
|
#include "list.h"
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "discovery.h"
|
#include "discovery.h"
|
||||||
@ -45,12 +46,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *tag;
|
|
||||||
size_t count;
|
|
||||||
} tagstats_t;
|
|
||||||
|
|
||||||
|
|
||||||
/* _\|/_
|
/* _\|/_
|
||||||
(o o)
|
(o o)
|
||||||
+----oOO-{_}-OOo------------------------------------------------------------+
|
+----oOO-{_}-OOo------------------------------------------------------------+
|
||||||
@ -172,77 +167,6 @@ static int build_design(design_t **adesigns, const char *cld)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char *escape(const char *org, const int pLength)
|
|
||||||
{
|
|
||||||
char *result = (char *) calloc(1, 2 * strlen(org) + 1);
|
|
||||||
int orgIdx, resultIdx;
|
|
||||||
for (orgIdx = 0, resultIdx = 0; orgIdx < pLength; ++orgIdx, ++resultIdx) {
|
|
||||||
if (org[orgIdx] == '\\' || org[orgIdx] == '"') {
|
|
||||||
result[resultIdx++] = '\\';
|
|
||||||
}
|
|
||||||
result[resultIdx] = org[orgIdx];
|
|
||||||
}
|
|
||||||
result[resultIdx] = '\0';
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int style_sort(const void *p1, const void *p2)
|
|
||||||
{
|
|
||||||
return strcasecmp((const char *) ((*((design_t **) p1))->name),
|
|
||||||
(const char *) ((*((design_t **) p2))->name));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a string listing all the names of a design, for example `"ada-cmt alias lua-cmt, sql-cmt"`.
|
|
||||||
* @param design pointer to the design
|
|
||||||
* @return the string of names, for which memory was allocated
|
|
||||||
*/
|
|
||||||
static char *names(design_t *design)
|
|
||||||
{
|
|
||||||
size_t siz = strlen(design->name);
|
|
||||||
size_t num_aliases = 0;
|
|
||||||
while(design->aliases[num_aliases] != NULL) {
|
|
||||||
siz += strlen(design->aliases[num_aliases]);
|
|
||||||
if (num_aliases > 0) {
|
|
||||||
siz += 2; // ", "
|
|
||||||
}
|
|
||||||
++num_aliases;
|
|
||||||
}
|
|
||||||
if (num_aliases > 0) {
|
|
||||||
siz += 7; // " alias "
|
|
||||||
}
|
|
||||||
|
|
||||||
char *result = (char *) malloc (siz + 1);
|
|
||||||
if (result == NULL) {
|
|
||||||
perror(PROJECT);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
strcpy(result, design->name);
|
|
||||||
|
|
||||||
if (num_aliases > 0) {
|
|
||||||
char *p = result + strlen(design->name);
|
|
||||||
strcpy(p, " alias ");
|
|
||||||
p += 7;
|
|
||||||
|
|
||||||
for (size_t aidx = 0; design->aliases[aidx] != NULL; ++aidx) {
|
|
||||||
strcpy(p, design->aliases[aidx]);
|
|
||||||
p += strlen(design->aliases[aidx]);
|
|
||||||
|
|
||||||
if (aidx < num_aliases - 1) {
|
|
||||||
strcpy(p, ", ");
|
|
||||||
p += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int query_is_undoc()
|
int query_is_undoc()
|
||||||
{
|
{
|
||||||
return opt.query != NULL && strcmp(opt.query[0], QUERY_UNDOC) == 0 && opt.query[1] == NULL;
|
return opt.query != NULL && strcmp(opt.query[0], QUERY_UNDOC) == 0 && opt.query[1] == NULL;
|
||||||
@ -288,300 +212,6 @@ static int filter_by_tag(char **tags)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void count_tag(char *tag, tagstats_t **tagstats, size_t *num_tags)
|
|
||||||
{
|
|
||||||
if (*tagstats != NULL) {
|
|
||||||
for (size_t i = 0; i < (*num_tags); ++i) {
|
|
||||||
if (strcasecmp((*tagstats)[i].tag, tag) == 0) {
|
|
||||||
++((*tagstats)[i].count);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++(*num_tags);
|
|
||||||
*tagstats = realloc(*tagstats, (*num_tags) * sizeof(tagstats_t));
|
|
||||||
(*tagstats)[(*num_tags) - 1].tag = tag;
|
|
||||||
(*tagstats)[(*num_tags) - 1].count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int tagstats_sort(const void *p1, const void *p2)
|
|
||||||
{
|
|
||||||
return strcasecmp(((tagstats_t *) p1)->tag, ((tagstats_t *) p2)->tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void print_tags(tagstats_t *tagstats, size_t num_tags)
|
|
||||||
{
|
|
||||||
if (tagstats != NULL) {
|
|
||||||
qsort(tagstats, num_tags, sizeof(tagstats_t), tagstats_sort);
|
|
||||||
for (size_t tidx = 0; tidx < num_tags; ++tidx) {
|
|
||||||
if (tidx > 0) {
|
|
||||||
fprintf(opt.outfile, " | ");
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "%s (%d)", tagstats[tidx].tag, (int) tagstats[tidx].count);
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "%s", opt.eol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
if (opt.design_choice_by_user) {
|
|
||||||
|
|
||||||
design_t *d = opt.design;
|
|
||||||
int sstart = 0;
|
|
||||||
size_t w = 0;
|
|
||||||
char space[LINE_MAX_BYTES + 1];
|
|
||||||
|
|
||||||
memset(&space, ' ', LINE_MAX_BYTES);
|
|
||||||
space[LINE_MAX_BYTES] = '\0';
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Complete Design Information for \"%s\":%s", d->name, opt.eol);
|
|
||||||
fprintf(opt.outfile, "-----------------------------------");
|
|
||||||
for (i = strlen(d->name); i > 0; --i) {
|
|
||||||
fprintf(opt.outfile, "-");
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "%s", opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Alias Names: ");
|
|
||||||
size_t aidx = 0;
|
|
||||||
while(d->aliases[aidx] != NULL) {
|
|
||||||
fprintf(opt.outfile, "%s%s", aidx > 0 ? ", " : "", d->aliases[aidx]);
|
|
||||||
++aidx;
|
|
||||||
}
|
|
||||||
if (aidx == 0) {
|
|
||||||
fprintf(opt.outfile, "none");
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "%s", opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Author: %s%s",
|
|
||||||
d->author ? d->author : "(unknown author)", opt.eol);
|
|
||||||
fprintf(opt.outfile, "Original Designer: %s%s",
|
|
||||||
d->designer ? d->designer : "(unknown artist)", opt.eol);
|
|
||||||
fprintf(opt.outfile, "Creation Date: %s%s",
|
|
||||||
d->created ? d->created : "(unknown)", opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Current Revision: %s%s%s%s",
|
|
||||||
d->revision ? d->revision : "",
|
|
||||||
d->revision && d->revdate ? " as of " : "",
|
|
||||||
d->revdate ? d->revdate : (d->revision ? "" : "(unknown)"), opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Configuration File: %s%s", d->defined_in, opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Indentation Mode: ");
|
|
||||||
switch (d->indentmode) {
|
|
||||||
case 'b':
|
|
||||||
fprintf(opt.outfile, "box (indent box)%s", opt.eol);
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
fprintf(opt.outfile, "text (retain indentation inside of box)%s", opt.eol);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(opt.outfile, "none (discard indentation)%s", opt.eol);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Replacement Rules: ");
|
|
||||||
if (d->anz_reprules > 0) {
|
|
||||||
for (i = 0; i < (int) d->anz_reprules; ++i) {
|
|
||||||
fprintf(opt.outfile, "%d. (%s) \"%s\" WITH \"%s\"%s", i + 1,
|
|
||||||
d->reprules[i].mode == 'g' ? "glob" : "once",
|
|
||||||
d->reprules[i].search, d->reprules[i].repstr, opt.eol);
|
|
||||||
if (i < (int) d->anz_reprules - 1) {
|
|
||||||
fprintf(opt.outfile, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(opt.outfile, "none%s", opt.eol);
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "Reversion Rules: ");
|
|
||||||
if (d->anz_revrules > 0) {
|
|
||||||
for (i = 0; i < (int) d->anz_revrules; ++i) {
|
|
||||||
fprintf(opt.outfile, "%d. (%s) \"%s\" TO \"%s\"%s", i + 1,
|
|
||||||
d->revrules[i].mode == 'g' ? "glob" : "once",
|
|
||||||
d->revrules[i].search, d->revrules[i].repstr, opt.eol);
|
|
||||||
if (i < (int) d->anz_revrules - 1) {
|
|
||||||
fprintf(opt.outfile, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(opt.outfile, "none%s", opt.eol);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Minimum Box Dimensions: %d x %d (width x height)%s",
|
|
||||||
(int) d->minwidth, (int) d->minheight, opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Default Padding: ");
|
|
||||||
if (d->padding[BTOP] || d->padding[BRIG]
|
|
||||||
|| d->padding[BBOT] || d->padding[BLEF]) {
|
|
||||||
if (d->padding[BLEF]) {
|
|
||||||
fprintf(opt.outfile, "left %d", d->padding[BLEF]);
|
|
||||||
if (d->padding[BTOP] || d->padding[BRIG] || d->padding[BBOT]) {
|
|
||||||
fprintf(opt.outfile, ", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d->padding[BTOP]) {
|
|
||||||
fprintf(opt.outfile, "top %d", d->padding[BTOP]);
|
|
||||||
if (d->padding[BRIG] || d->padding[BBOT]) {
|
|
||||||
fprintf(opt.outfile, ", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d->padding[BRIG]) {
|
|
||||||
fprintf(opt.outfile, "right %d", d->padding[BRIG]);
|
|
||||||
if (d->padding[BBOT]) {
|
|
||||||
fprintf(opt.outfile, ", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (d->padding[BBOT]) {
|
|
||||||
fprintf(opt.outfile, "bottom %d", d->padding[BBOT]);
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "%s", opt.eol);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(opt.outfile, "none%s", opt.eol);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Default Killblank: %s%s",
|
|
||||||
empty_side(opt.design->shape, BTOP) && empty_side(opt.design->shape, BBOT) ? "no" : "yes", opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Tags: ");
|
|
||||||
size_t tidx = 0;
|
|
||||||
while(d->tags[tidx] != NULL) {
|
|
||||||
fprintf(opt.outfile, "%s%s", tidx > 0 ? ", " : "", d->tags[tidx]);
|
|
||||||
++tidx;
|
|
||||||
}
|
|
||||||
if (tidx == 0) {
|
|
||||||
fprintf(opt.outfile, "none");
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "%s", opt.eol);
|
|
||||||
|
|
||||||
fprintf(opt.outfile, "Elastic Shapes: ");
|
|
||||||
sstart = 0;
|
|
||||||
for (i = 0; i < ANZ_SHAPES; ++i) {
|
|
||||||
if (isempty(d->shape + i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (d->shape[i].elastic) {
|
|
||||||
fprintf(opt.outfile, "%s%s", sstart ? ", " : "", shape_name[i]);
|
|
||||||
sstart = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fprintf(opt.outfile, "%s", opt.eol);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Display all shapes
|
|
||||||
*/
|
|
||||||
if (query_is_undoc()) {
|
|
||||||
fprintf(opt.outfile, "Sample:%s%s%s", opt.eol, d->sample, opt.eol);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int first_shape = 1;
|
|
||||||
for (i = 0; i < ANZ_SHAPES; ++i) {
|
|
||||||
if (isdeepempty(d->shape + i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (w = 0; w < d->shape[i].height; ++w) {
|
|
||||||
char *escaped_line = escape(d->shape[i].chars[w], d->shape[i].width);
|
|
||||||
fprintf(opt.outfile, "%-24s%3s%c \"%s\"%c%s",
|
|
||||||
(first_shape == 1 && w == 0 ? "Defined Shapes:" : ""),
|
|
||||||
(w == 0 ? shape_name[i] : ""), (w == 0 ? ':' : ' '),
|
|
||||||
escaped_line,
|
|
||||||
(w < d->shape[i].height - 1 ? ',' : ' '),
|
|
||||||
opt.eol
|
|
||||||
);
|
|
||||||
BFREE (escaped_line);
|
|
||||||
}
|
|
||||||
first_shape = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
else {
|
|
||||||
tagstats_t *tagstats = NULL;
|
|
||||||
size_t num_tags = 0;
|
|
||||||
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) {
|
|
||||||
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%s%s, coded by %s:%s%s%s%s%s", all_names, opt.eol,
|
|
||||||
list[i]->designer, list[i]->author, opt.eol, opt.eol,
|
|
||||||
list[i]->sample, opt.eol, opt.eol);
|
|
||||||
}
|
|
||||||
else if (list[i]->designer) {
|
|
||||||
fprintf(opt.outfile, "%s%s%s:%s%s%s%s%s", all_names, opt.eol,
|
|
||||||
list[i]->designer, opt.eol, opt.eol,
|
|
||||||
list[i]->sample, opt.eol, opt.eol);
|
|
||||||
}
|
|
||||||
else if (list[i]->author) {
|
|
||||||
fprintf(opt.outfile, "%s%sunknown artist, coded by %s:%s%s%s%s%s", all_names, opt.eol,
|
|
||||||
list[i]->author, opt.eol, opt.eol,
|
|
||||||
list[i]->sample, opt.eol, opt.eol);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(opt.outfile, "%s:%s%s%s%s%s", all_names, opt.eol, opt.eol,
|
|
||||||
list[i]->sample, opt.eol, opt.eol);
|
|
||||||
}
|
|
||||||
BFREE(all_names);
|
|
||||||
|
|
||||||
for (size_t tidx = 0; list[i]->tags[tidx] != NULL; ++tidx) {
|
|
||||||
count_tag(list[i]->tags[tidx], &tagstats, &num_tags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BFREE(list);
|
|
||||||
|
|
||||||
print_tags(tagstats, num_tags);
|
|
||||||
BFREE(tagstats);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int query_by_tag()
|
static int query_by_tag()
|
||||||
{
|
{
|
||||||
design_t **list = sort_designs_by_name(); /* temp list for sorting */
|
design_t **list = sort_designs_by_name(); /* temp list for sorting */
|
||||||
@ -1028,10 +658,10 @@ int main(int argc, char *argv[])
|
|||||||
opt.design = designs;
|
opt.design = designs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If "-l" option was given, list styles and exit.
|
* If "-l" option was given, list designs and exit.
|
||||||
*/
|
*/
|
||||||
if (opt.l) {
|
if (opt.l) {
|
||||||
rc = list_styles();
|
rc = list_designs();
|
||||||
exit(rc);
|
exit(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
400
src/list.c
Normal file
400
src/list.c
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List design information about a single design or about all designs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#include "boxes.h"
|
||||||
|
#include "parsing.h"
|
||||||
|
#include "tools.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *tag;
|
||||||
|
size_t count;
|
||||||
|
} tagstats_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void analyze_names(design_t *design, size_t *r_num_aliases, size_t *r_num_chars)
|
||||||
|
{
|
||||||
|
size_t siz = strlen(design->name);
|
||||||
|
size_t num_aliases = 0;
|
||||||
|
while(design->aliases[num_aliases] != NULL) {
|
||||||
|
siz += strlen(design->aliases[num_aliases]);
|
||||||
|
if (num_aliases > 0) {
|
||||||
|
siz += 2; // ", "
|
||||||
|
}
|
||||||
|
++num_aliases;
|
||||||
|
}
|
||||||
|
if (num_aliases > 0) {
|
||||||
|
siz += 7; // " alias "
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_num_aliases = num_aliases;
|
||||||
|
*r_num_chars = siz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a string listing all the names of a design, for example `"ada-cmt alias lua-cmt, sql-cmt"`.
|
||||||
|
* @param design pointer to the design
|
||||||
|
* @return the string of names, for which memory was allocated
|
||||||
|
*/
|
||||||
|
static char *names(design_t *design)
|
||||||
|
{
|
||||||
|
size_t siz;
|
||||||
|
size_t num_aliases;
|
||||||
|
analyze_names(design, &num_aliases, &siz);
|
||||||
|
|
||||||
|
char *result = (char *) malloc (siz + 1);
|
||||||
|
if (result == NULL) {
|
||||||
|
perror(PROJECT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
strcpy(result, design->name);
|
||||||
|
|
||||||
|
if (num_aliases > 0) {
|
||||||
|
char *p = result + strlen(design->name);
|
||||||
|
strcpy(p, " alias ");
|
||||||
|
p += 7; // " alias "
|
||||||
|
|
||||||
|
for (size_t aidx = 0; design->aliases[aidx] != NULL; ++aidx) {
|
||||||
|
strcpy(p, design->aliases[aidx]);
|
||||||
|
p += strlen(design->aliases[aidx]);
|
||||||
|
|
||||||
|
if (aidx < num_aliases - 1) {
|
||||||
|
strcpy(p, ", ");
|
||||||
|
p += 2; // ", "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int style_sort(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
return strcasecmp((const char *) ((*((design_t **) p1))->name),
|
||||||
|
(const char *) ((*((design_t **) p2))->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void count_tag(char *tag, tagstats_t **tagstats, size_t *num_tags)
|
||||||
|
{
|
||||||
|
if (*tagstats != NULL) {
|
||||||
|
for (size_t i = 0; i < (*num_tags); ++i) {
|
||||||
|
if (strcasecmp((*tagstats)[i].tag, tag) == 0) {
|
||||||
|
++((*tagstats)[i].count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++(*num_tags);
|
||||||
|
*tagstats = realloc(*tagstats, (*num_tags) * sizeof(tagstats_t));
|
||||||
|
(*tagstats)[(*num_tags) - 1].tag = tag;
|
||||||
|
(*tagstats)[(*num_tags) - 1].count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int tagstats_sort(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
return strcasecmp(((tagstats_t *) p1)->tag, ((tagstats_t *) p2)->tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void print_tags(tagstats_t *tagstats, size_t num_tags)
|
||||||
|
{
|
||||||
|
if (tagstats != NULL) {
|
||||||
|
qsort(tagstats, num_tags, sizeof(tagstats_t), tagstats_sort);
|
||||||
|
for (size_t tidx = 0; tidx < num_tags; ++tidx) {
|
||||||
|
if (tidx > 0) {
|
||||||
|
fprintf(opt.outfile, " | ");
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "%s (%d)", tagstats[tidx].tag, (int) tagstats[tidx].count);
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "%s", opt.eol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static char *escape(const char *org, const int pLength)
|
||||||
|
{
|
||||||
|
char *result = (char *) calloc(1, 2 * strlen(org) + 1);
|
||||||
|
int orgIdx, resultIdx;
|
||||||
|
for (orgIdx = 0, resultIdx = 0; orgIdx < pLength; ++orgIdx, ++resultIdx) {
|
||||||
|
if (org[orgIdx] == '\\' || org[orgIdx] == '"') {
|
||||||
|
result[resultIdx++] = '\\';
|
||||||
|
}
|
||||||
|
result[resultIdx] = org[orgIdx];
|
||||||
|
}
|
||||||
|
result[resultIdx] = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void print_design_details(design_t *d)
|
||||||
|
{
|
||||||
|
fprintf(opt.outfile, "Complete Design Information for \"%s\":%s", d->name, opt.eol);
|
||||||
|
fprintf(opt.outfile, "-----------------------------------");
|
||||||
|
for (int i = strlen(d->name); i > 0; --i) {
|
||||||
|
fprintf(opt.outfile, "-");
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "%s", opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Alias Names: ");
|
||||||
|
size_t aidx = 0;
|
||||||
|
while(d->aliases[aidx] != NULL) {
|
||||||
|
fprintf(opt.outfile, "%s%s", aidx > 0 ? ", " : "", d->aliases[aidx]);
|
||||||
|
++aidx;
|
||||||
|
}
|
||||||
|
if (aidx == 0) {
|
||||||
|
fprintf(opt.outfile, "none");
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "%s", opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Author: %s%s", d->author ? d->author : "(unknown author)", opt.eol);
|
||||||
|
fprintf(opt.outfile, "Original Designer: %s%s", d->designer ? d->designer : "(unknown artist)", opt.eol);
|
||||||
|
fprintf(opt.outfile, "Creation Date: %s%s", d->created ? d->created : "(unknown)", opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Current Revision: %s%s%s%s",
|
||||||
|
d->revision ? d->revision : "",
|
||||||
|
d->revision && d->revdate ? " as of " : "",
|
||||||
|
d->revdate ? d->revdate : (d->revision ? "" : "(unknown)"), opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Configuration File: %s%s", d->defined_in, opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Indentation Mode: ");
|
||||||
|
switch (d->indentmode) {
|
||||||
|
case 'b':
|
||||||
|
fprintf(opt.outfile, "box (indent box)%s", opt.eol);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
fprintf(opt.outfile, "text (retain indentation inside of box)%s", opt.eol);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(opt.outfile, "none (discard indentation)%s", opt.eol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Replacement Rules: ");
|
||||||
|
if (d->anz_reprules > 0) {
|
||||||
|
for (int i = 0; i < (int) d->anz_reprules; ++i) {
|
||||||
|
fprintf(opt.outfile, "%d. (%s) \"%s\" WITH \"%s\"%s", i + 1,
|
||||||
|
d->reprules[i].mode == 'g' ? "glob" : "once",
|
||||||
|
d->reprules[i].search, d->reprules[i].repstr, opt.eol);
|
||||||
|
if (i < (int) d->anz_reprules - 1) {
|
||||||
|
fprintf(opt.outfile, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(opt.outfile, "none%s", opt.eol);
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "Reversion Rules: ");
|
||||||
|
if (d->anz_revrules > 0) {
|
||||||
|
for (int i = 0; i < (int) d->anz_revrules; ++i) {
|
||||||
|
fprintf(opt.outfile, "%d. (%s) \"%s\" TO \"%s\"%s", i + 1,
|
||||||
|
d->revrules[i].mode == 'g' ? "glob" : "once",
|
||||||
|
d->revrules[i].search, d->revrules[i].repstr, opt.eol);
|
||||||
|
if (i < (int) d->anz_revrules - 1) {
|
||||||
|
fprintf(opt.outfile, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(opt.outfile, "none%s", opt.eol);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Minimum Box Dimensions: %d x %d (width x height)%s",
|
||||||
|
(int) d->minwidth, (int) d->minheight, opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Default Padding: ");
|
||||||
|
if (d->padding[BTOP] || d->padding[BRIG] || d->padding[BBOT] || d->padding[BLEF]) {
|
||||||
|
if (d->padding[BLEF]) {
|
||||||
|
fprintf(opt.outfile, "left %d", d->padding[BLEF]);
|
||||||
|
if (d->padding[BTOP] || d->padding[BRIG] || d->padding[BBOT]) {
|
||||||
|
fprintf(opt.outfile, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d->padding[BTOP]) {
|
||||||
|
fprintf(opt.outfile, "top %d", d->padding[BTOP]);
|
||||||
|
if (d->padding[BRIG] || d->padding[BBOT]) {
|
||||||
|
fprintf(opt.outfile, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d->padding[BRIG]) {
|
||||||
|
fprintf(opt.outfile, "right %d", d->padding[BRIG]);
|
||||||
|
if (d->padding[BBOT]) {
|
||||||
|
fprintf(opt.outfile, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d->padding[BBOT]) {
|
||||||
|
fprintf(opt.outfile, "bottom %d", d->padding[BBOT]);
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "%s", opt.eol);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(opt.outfile, "none%s", opt.eol);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Default Killblank: %s%s",
|
||||||
|
empty_side(opt.design->shape, BTOP) && empty_side(opt.design->shape, BBOT) ? "no" : "yes", opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Tags: ");
|
||||||
|
size_t tidx = 0;
|
||||||
|
while(d->tags[tidx] != NULL) {
|
||||||
|
fprintf(opt.outfile, "%s%s", tidx > 0 ? ", " : "", d->tags[tidx]);
|
||||||
|
++tidx;
|
||||||
|
}
|
||||||
|
if (tidx == 0) {
|
||||||
|
fprintf(opt.outfile, "none");
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "%s", opt.eol);
|
||||||
|
|
||||||
|
fprintf(opt.outfile, "Elastic Shapes: ");
|
||||||
|
int sstart = 0;
|
||||||
|
for (int i = 0; i < ANZ_SHAPES; ++i) {
|
||||||
|
if (isempty(d->shape + i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (d->shape[i].elastic) {
|
||||||
|
fprintf(opt.outfile, "%s%s", sstart ? ", " : "", shape_name[i]);
|
||||||
|
sstart = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(opt.outfile, "%s", opt.eol);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Display all shapes
|
||||||
|
*/
|
||||||
|
if (query_is_undoc()) {
|
||||||
|
fprintf(opt.outfile, "Sample:%s%s%s", opt.eol, d->sample, opt.eol);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int first_shape = 1;
|
||||||
|
for (int i = 0; i < ANZ_SHAPES; ++i) {
|
||||||
|
if (isdeepempty(d->shape + i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (size_t w = 0; w < d->shape[i].height; ++w) {
|
||||||
|
char *escaped_line = escape(d->shape[i].chars[w], d->shape[i].width);
|
||||||
|
fprintf(opt.outfile, "%-24s%3s%c \"%s\"%c%s",
|
||||||
|
(first_shape == 1 && w == 0 ? "Defined Shapes:" : ""),
|
||||||
|
(w == 0 ? shape_name[i] : ""), (w == 0 ? ':' : ' '),
|
||||||
|
escaped_line,
|
||||||
|
(w < d->shape[i].height - 1 ? ',' : ' '),
|
||||||
|
opt.eol
|
||||||
|
);
|
||||||
|
BFREE (escaped_line);
|
||||||
|
}
|
||||||
|
first_shape = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int list_designs()
|
||||||
|
{
|
||||||
|
if (opt.design_choice_by_user) {
|
||||||
|
print_design_details(opt.design);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
tagstats_t *tagstats = NULL;
|
||||||
|
size_t num_tags = 0;
|
||||||
|
design_t **list = sort_designs_by_name(); /* temp list for sorting */
|
||||||
|
if (list == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print_design_list_header();
|
||||||
|
|
||||||
|
for (int i = 0; i < anz_designs; ++i) {
|
||||||
|
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%s%s, coded by %s:%s%s%s%s%s", all_names, opt.eol,
|
||||||
|
list[i]->designer, list[i]->author, opt.eol, opt.eol,
|
||||||
|
list[i]->sample, opt.eol, opt.eol);
|
||||||
|
}
|
||||||
|
else if (list[i]->designer) {
|
||||||
|
fprintf(opt.outfile, "%s%s%s:%s%s%s%s%s", all_names, opt.eol,
|
||||||
|
list[i]->designer, opt.eol, opt.eol,
|
||||||
|
list[i]->sample, opt.eol, opt.eol);
|
||||||
|
}
|
||||||
|
else if (list[i]->author) {
|
||||||
|
fprintf(opt.outfile, "%s%sunknown artist, coded by %s:%s%s%s%s%s", all_names, opt.eol,
|
||||||
|
list[i]->author, opt.eol, opt.eol,
|
||||||
|
list[i]->sample, opt.eol, opt.eol);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(opt.outfile, "%s:%s%s%s%s%s", all_names, opt.eol, opt.eol,
|
||||||
|
list[i]->sample, opt.eol, opt.eol);
|
||||||
|
}
|
||||||
|
BFREE(all_names);
|
||||||
|
|
||||||
|
for (size_t tidx = 0; list[i]->tags[tidx] != NULL; ++tidx) {
|
||||||
|
count_tag(list[i]->tags[tidx], &tagstats, &num_tags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BFREE(list);
|
||||||
|
|
||||||
|
print_tags(tagstats, num_tags);
|
||||||
|
BFREE(tagstats);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*EOF*/ /* vim: set sw=4: */
|
48
src/list.h
Normal file
48
src/list.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List design information about a single design or about all designs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIST_H
|
||||||
|
#define LIST_H
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a sorted shallow copy of the global 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.
|
||||||
|
*/
|
||||||
|
design_t **sort_designs_by_name();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a sorted listing of available box designs.
|
||||||
|
* Uses design name from BOX spec and sample picture plus author.
|
||||||
|
* @returns != 0 on error (out of memory);
|
||||||
|
* == 0 on success
|
||||||
|
*/
|
||||||
|
int list_designs();
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*EOF*/ /* vim: set cindent sw=4: */
|
Reference in New Issue
Block a user