mirror of
https://github.com/ascii-boxes/boxes.git
synced 2024-12-12 09:51:10 +01:00
Add new test case for nearly blank corners and indentation removal
... including some fixes to make this work.
This commit is contained in:
parent
c146373601
commit
76c4e10cd1
@ -108,6 +108,7 @@ static int build_design(design_t **adesigns, const char *cld)
|
|||||||
bxstr_t *cldW = bxs_from_unicode(cld_u32);
|
bxstr_t *cldW = bxs_from_unicode(cld_u32);
|
||||||
BFREE(cld_u32);
|
BFREE(cld_u32);
|
||||||
|
|
||||||
|
dp->shape[W].name = W;
|
||||||
dp->shape[W].height = 1;
|
dp->shape[W].height = 1;
|
||||||
dp->shape[W].width = cldW->num_columns;
|
dp->shape[W].width = cldW->num_columns;
|
||||||
dp->shape[W].elastic = 1;
|
dp->shape[W].elastic = 1;
|
||||||
@ -154,6 +155,7 @@ static int build_design(design_t **adesigns, const char *cld)
|
|||||||
fprintf(stderr, "%s: internal error\n", PROJECT);
|
fprintf(stderr, "%s: internal error\n", PROJECT);
|
||||||
return 1; /* never happens ;-) */
|
return 1; /* never happens ;-) */
|
||||||
}
|
}
|
||||||
|
c->name = i;
|
||||||
|
|
||||||
rc = genshape(c->width, c->height, &(c->chars), &(c->mbcs));
|
rc = genshape(c->width, c->height, &(c->chars), &(c->mbcs));
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#ifndef BOXES_H
|
#ifndef BOXES_H
|
||||||
#define BOXES_H
|
#define BOXES_H
|
||||||
|
|
||||||
/* #define DEBUG 1 */
|
#define DEBUG 1
|
||||||
/* #define REGEXP_DEBUG 1 */
|
/* #define REGEXP_DEBUG 1 */
|
||||||
/* #define PARSER_DEBUG 1 */
|
/* #define PARSER_DEBUG 1 */
|
||||||
/* #define LEXER_DEBUG 1 */
|
/* #define LEXER_DEBUG 1 */
|
||||||
|
13
src/detect.c
13
src/detect.c
@ -383,20 +383,21 @@ static size_t find_horizontal_shape(design_t *current_design, comparison_t comp_
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *shape_relevant = prepare_comp_shape(current_design, hshape, j, comp_type, 0, 0);
|
uint32_t *shape_relevant = prepare_comp_shape(current_design, hshape, j, comp_type,
|
||||||
|
is_blank_leftward(current_design, hshape, j),
|
||||||
|
is_blank_rightward(current_design, hshape, j));
|
||||||
size_t length_relevant = u32_strlen(shape_relevant);
|
size_t length_relevant = u32_strlen(shape_relevant);
|
||||||
|
|
||||||
for (size_t k = 0; k < current_design->shape[hshape].height; ++k) {
|
for (size_t k = 0; k < current_design->shape[hshape].height; ++k) {
|
||||||
size_t a = k;
|
size_t line_idx = k;
|
||||||
if (hshape >= SSE && hshape <= SSW) {
|
if (hshape >= SSE && hshape <= SSW) {
|
||||||
a += input.num_lines - current_design->shape[hshape].height;
|
line_idx += input.num_lines - current_design->shape[hshape].height;
|
||||||
}
|
}
|
||||||
if (a >= input.num_lines) {
|
if (line_idx >= input.num_lines) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0, NULL, NULL);
|
uint32_t *input_relevant = prepare_comp_input(line_idx, 1, comp_type, 0, NULL, NULL);
|
||||||
/* CHECK this eats blank NW corners */
|
|
||||||
uint32_t *p = u32_strstr(input_relevant, shape_relevant);
|
uint32_t *p = u32_strstr(input_relevant, shape_relevant);
|
||||||
if (p) {
|
if (p) {
|
||||||
if (current_design->shape[hshape].elastic) {
|
if (current_design->shape[hshape].elastic) {
|
||||||
|
@ -602,6 +602,13 @@ int action_finalize_shapes(pass_to_bison *bison_args)
|
|||||||
(int) curdes.minwidth, (int) curdes.minheight);
|
(int) curdes.minwidth, (int) curdes.minheight);
|
||||||
fprintf(stderr, " Parser: Maximum shape height: %d\n", (int) curdes.maxshapeheight);
|
fprintf(stderr, " Parser: Maximum shape height: %d\n", (int) curdes.maxshapeheight);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set name of each shape
|
||||||
|
*/
|
||||||
|
for (i = 0; i < NUM_SHAPES; ++i) {
|
||||||
|
curdes.shape[i].name = i;
|
||||||
|
}
|
||||||
return RC_SUCCESS;
|
return RC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
224
src/shape.c
224
src/shape.c
@ -24,9 +24,9 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "boxes.h"
|
||||||
#include "bxstring.h"
|
#include "bxstring.h"
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
#include "boxes.h"
|
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
|
|
||||||
@ -333,4 +333,226 @@ int empty_side(sentry_t *sarr, const int aside)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int is_west(sentry_t *shape, int include_corners)
|
||||||
|
{
|
||||||
|
size_t offset = include_corners ? 0 : 1;
|
||||||
|
for (size_t i = offset; i < SHAPES_PER_SIDE - offset; i++) {
|
||||||
|
if (west_side[i] == shape->name) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int is_east(sentry_t *shape, int include_corners)
|
||||||
|
{
|
||||||
|
size_t offset = include_corners ? 0 : 1;
|
||||||
|
for (size_t i = offset; i < SHAPES_PER_SIDE - offset; i++) {
|
||||||
|
if (east_side[i] == shape->name) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int find_in_horiz(shape_t side[], shape_t shape_name)
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
for (size_t i = 0; i < SHAPES_PER_SIDE; i++) {
|
||||||
|
if (side[i] == shape_name) {
|
||||||
|
result = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int find_in_north(shape_t shape_name)
|
||||||
|
{
|
||||||
|
return find_in_horiz(north_side, shape_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int find_in_south(shape_t shape_name)
|
||||||
|
{
|
||||||
|
return find_in_horiz(south_side_rev, shape_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int *new_blankward_cache(const size_t shape_height)
|
||||||
|
{
|
||||||
|
int *result = (int *) calloc(shape_height, sizeof(int));
|
||||||
|
for (size_t i = 0; i < shape_height; i++) {
|
||||||
|
result[i] = -1;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int is_blank_leftward(design_t *current_design, const shape_t shape, const size_t shape_line_idx)
|
||||||
|
{
|
||||||
|
if (current_design == NULL) {
|
||||||
|
return 0; /* this would be a bug */
|
||||||
|
}
|
||||||
|
sentry_t *shape_data = current_design->shape + shape;
|
||||||
|
if (shape_line_idx >= shape_data->height) {
|
||||||
|
return 0; /* this would be a bug */
|
||||||
|
}
|
||||||
|
if (shape_data->blank_leftward != NULL && shape_data->blank_leftward[shape_line_idx] >= 0) {
|
||||||
|
return shape_data->blank_leftward[shape_line_idx]; /* cached value available */
|
||||||
|
}
|
||||||
|
if (shape_data->blank_leftward == NULL) {
|
||||||
|
shape_data->blank_leftward = new_blankward_cache(shape_data->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = -1;
|
||||||
|
if (is_west(shape_data, 1)) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else if (is_east(shape_data, 0)) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
shape_t *side = north_side;
|
||||||
|
int pos = find_in_north(shape);
|
||||||
|
if (pos < 0) {
|
||||||
|
side = south_side_rev;
|
||||||
|
pos = find_in_south(shape);
|
||||||
|
}
|
||||||
|
result = 1;
|
||||||
|
for (size_t i = 0; i < (size_t) pos; i++) {
|
||||||
|
sentry_t *tshape = current_design->shape + side[i];
|
||||||
|
if (tshape->mbcs != NULL && !bxs_is_blank(tshape->mbcs[shape_line_idx])) {
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shape_data->blank_leftward[shape_line_idx] = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO HERE is_blank_rightward() and is_blank_leftward() are nearly identical -> consolidate
|
||||||
|
int is_blank_rightward(design_t *current_design, const shape_t shape, const size_t shape_line_idx)
|
||||||
|
{
|
||||||
|
if (current_design == NULL) {
|
||||||
|
return 0; /* this would be a bug */
|
||||||
|
}
|
||||||
|
sentry_t *shape_data = current_design->shape + shape;
|
||||||
|
if (shape_line_idx >= shape_data->height) {
|
||||||
|
return 0; /* this would be a bug */
|
||||||
|
}
|
||||||
|
if (shape_data->blank_rightward != NULL && shape_data->blank_rightward[shape_line_idx] >= 0) {
|
||||||
|
return shape_data->blank_rightward[shape_line_idx]; /* cached value available */
|
||||||
|
}
|
||||||
|
if (shape_data->blank_rightward == NULL) {
|
||||||
|
shape_data->blank_rightward = new_blankward_cache(shape_data->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = -1;
|
||||||
|
if (is_west(shape_data, 0)) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else if (is_east(shape_data, 1)) {
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
shape_t *side = north_side;
|
||||||
|
int pos = find_in_north(shape);
|
||||||
|
if (pos < 0) {
|
||||||
|
side = south_side_rev;
|
||||||
|
pos = find_in_south(shape);
|
||||||
|
}
|
||||||
|
result = 1;
|
||||||
|
for (size_t i = (size_t) pos + 1; i < SHAPES_PER_SIDE; i++) {
|
||||||
|
sentry_t *tshape = current_design->shape + side[i];
|
||||||
|
if (tshape->mbcs != NULL && !bxs_is_blank(tshape->mbcs[shape_line_idx])) {
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shape_data->blank_rightward[shape_line_idx] = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void debug_print_shape(sentry_t *shape)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (shape == NULL) {
|
||||||
|
fprintf(stderr, "NULL\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Shape %3s (%dx%d): elastic=%s, bl=",
|
||||||
|
shape_name[shape->name], (int) shape->width, (int) shape->height, shape->elastic ? "true" : "false");
|
||||||
|
if (shape->blank_leftward == NULL) {
|
||||||
|
fprintf(stderr, "NULL");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[");
|
||||||
|
for (size_t i = 0; i < shape->height; i++) {
|
||||||
|
fprintf(stderr, "%d%s", shape->blank_leftward[i],
|
||||||
|
shape->height > 0 && i < (shape->height - 1) ? ", " : "");
|
||||||
|
}
|
||||||
|
fprintf(stderr, "]");
|
||||||
|
}
|
||||||
|
fprintf(stderr, ", br=");
|
||||||
|
if (shape->blank_rightward == NULL) {
|
||||||
|
fprintf(stderr, "NULL");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[");
|
||||||
|
for (size_t i = 0; i < shape->height; i++) {
|
||||||
|
fprintf(stderr, "%d%s", shape->blank_rightward[i],
|
||||||
|
shape->height > 0 && i < (shape->height - 1) ? ", " : "");
|
||||||
|
}
|
||||||
|
fprintf(stderr, "]");
|
||||||
|
}
|
||||||
|
fprintf(stderr, ", ascii=");
|
||||||
|
if (shape->chars == NULL) {
|
||||||
|
fprintf(stderr, "NULL");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[");
|
||||||
|
for (size_t i = 0; i < shape->height; i++) {
|
||||||
|
fprintf(stderr, "%s%s%s%s", shape->chars[i] != NULL ? "\"" : "", shape->chars[i],
|
||||||
|
shape->chars[i] != NULL ? "\"" : "", (int) i < ((int) shape->height) - 1 ? ", " : "");
|
||||||
|
}
|
||||||
|
fprintf(stderr, "]");
|
||||||
|
}
|
||||||
|
fprintf(stderr, ", mbcs=");
|
||||||
|
if (shape->mbcs == NULL) {
|
||||||
|
fprintf(stderr, "NULL");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "[");
|
||||||
|
for (size_t i = 0; i < shape->height; i++) {
|
||||||
|
char *out_mbcs = bxs_to_output(shape->mbcs[i]);
|
||||||
|
fprintf(stderr, "%s%s%s%s", shape->mbcs[i] != NULL ? "\"" : "", out_mbcs,
|
||||||
|
shape->mbcs[i] != NULL ? "\"" : "", shape->height > 0 && i < (shape->height - 1) ? ", " : "");
|
||||||
|
BFREE(out_mbcs);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "]");
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
#else
|
||||||
|
UNUSED(shape);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* vim: set sw=4: */
|
/* vim: set sw=4: */
|
||||||
|
43
src/shape.h
43
src/shape.h
@ -46,14 +46,25 @@ extern shape_t *sides[NUM_SIDES];
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
shape_t name;
|
||||||
char **chars;
|
char **chars;
|
||||||
bxstr_t **mbcs;
|
bxstr_t **mbcs;
|
||||||
size_t height;
|
size_t height;
|
||||||
size_t width;
|
size_t width;
|
||||||
int elastic; /* elastic is used only in original definition */
|
|
||||||
|
/** elastic is used only in original definition */
|
||||||
|
int elastic;
|
||||||
|
|
||||||
|
/** For each shape line 0..height-1, a flag which is 1 if all shapes to the left of this shape are blank on the
|
||||||
|
* same shape line. Always 1 if the shape is part of the left (west) box side. */
|
||||||
|
int *blank_leftward;
|
||||||
|
|
||||||
|
/** For each shape line 0..height-1, a flag which is 1 if all shapes to the right of this shape are blank on the
|
||||||
|
* same shape line. Always 1 if the shape is part of the right (east) box side. */
|
||||||
|
int *blank_rightward;
|
||||||
} sentry_t;
|
} sentry_t;
|
||||||
|
|
||||||
#define SENTRY_INITIALIZER (sentry_t) {NULL, NULL, 0, 0, 0}
|
#define SENTRY_INITIALIZER (sentry_t) {NW, NULL, NULL, 0, 0, 0, NULL, NULL}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -72,6 +83,34 @@ size_t widest (const sentry_t *sarr, const int n, ...);
|
|||||||
int empty_side (sentry_t *sarr, const int aside);
|
int empty_side (sentry_t *sarr, const int aside);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if there are only blanks to the left of this shape on the given line. The result is cached in the shape.
|
||||||
|
* @param current_design the design whose shapes to use
|
||||||
|
* @param shape the shape for which to calculate "blank_leftward"
|
||||||
|
* @param shape_line_idx the index of the shape line to assess
|
||||||
|
* @return 1 if blank leftward, 0 otherwise. Will always return 1 if shape is part of the left (west) box side, and
|
||||||
|
* always 0 if shape is an east side shape (not a corner)
|
||||||
|
*/
|
||||||
|
int is_blank_leftward(design_t *current_design, const shape_t shape, const size_t shape_line_idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if there are only blanks to the right of this shape on the given line. The result is cached in the shape.
|
||||||
|
* @param current_design the design whose shapes to use
|
||||||
|
* @param shape the shape for which to calculate "blank_rightward"
|
||||||
|
* @param shape_line_idx the index of the shape line to assess
|
||||||
|
* @return 1 if blank rightward, 0 otherwise. Will always return 1 if shape is part of the right (east) box side, and
|
||||||
|
* always 0 if shape is a west side shape (not a corner)
|
||||||
|
*/
|
||||||
|
int is_blank_rightward(design_t *current_design, const shape_t shape, const size_t shape_line_idx);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print complete data about a shape to stderr for debugging.
|
||||||
|
* @param shape the shape whose data to print
|
||||||
|
*/
|
||||||
|
void debug_print_shape(sentry_t *shape);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /*SHAPE_H*/
|
#endif /*SHAPE_H*/
|
||||||
|
|
||||||
|
27
test/190_remove_blank_nw_lines.txt
Normal file
27
test/190_remove_blank_nw_lines.txt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
:DESC
|
||||||
|
Auto-detect the box design as 'capgirl', remove the box, and also remove the box indentation because `-i none`.
|
||||||
|
The resulting text will still appear a bit indented, but those are the spaces from inside the box!
|
||||||
|
Note that the NW corner is mostly blank (except its very bottom), which triggers some potential problems in the code.
|
||||||
|
|
||||||
|
:ARGS
|
||||||
|
--remove -i none
|
||||||
|
:INPUT
|
||||||
|
.-"```"-.
|
||||||
|
/_______; \
|
||||||
|
(_________)\|
|
||||||
|
/ / a a \ \(_)
|
||||||
|
/ ( \___/ ) \
|
||||||
|
_ooo\__\_____/__/____
|
||||||
|
/ \
|
||||||
|
| foobar |
|
||||||
|
\_________________ooo_/
|
||||||
|
/ \
|
||||||
|
/:.:.:.:.:.:.:\
|
||||||
|
| | |
|
||||||
|
\==|==/ jgs
|
||||||
|
/-'Y'-\
|
||||||
|
(__/ \__)
|
||||||
|
:OUTPUT-FILTER
|
||||||
|
:EXPECTED
|
||||||
|
foobar
|
||||||
|
:EOF
|
Loading…
Reference in New Issue
Block a user