Add new test case for nearly blank corners and indentation removal

... including some fixes to make this work.
This commit is contained in:
Thomas Jensen 2023-11-10 21:13:26 +01:00
parent c146373601
commit 76c4e10cd1
No known key found for this signature in database
GPG Key ID: A4ACEE270D0FB7DB
7 changed files with 308 additions and 10 deletions

View File

@ -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) {

View File

@ -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 */

View File

@ -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) {

View File

@ -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;
} }

View File

@ -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: */

View File

@ -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*/

View 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