mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-06-21 02:08:02 +02:00
Rewrite 'remove' module to enable unicode, double-with chars, and coloring
This commit is contained in:
parent
9511d18bc1
commit
4175d72bc8
@ -121,7 +121,7 @@ parser.o: parser.c boxes.h bxstring.h lex.yy.h parsecode.h parser.h parsing.h
|
|||||||
parsing.o: parsing.c parsing.h bxstring.h parser.h lex.yy.h boxes.h tools.h config.h | check_dir
|
parsing.o: parsing.c parsing.h bxstring.h parser.h lex.yy.h boxes.h tools.h config.h | check_dir
|
||||||
query.o: query.c query.h boxes.h list.h tools.h config.h | check_dir
|
query.o: query.c query.h boxes.h list.h tools.h config.h | check_dir
|
||||||
regulex.o: regulex.c regulex.h boxes.h tools.h unicode.h config.h | check_dir
|
regulex.o: regulex.c regulex.h boxes.h tools.h unicode.h config.h | check_dir
|
||||||
remove.o: remove.c remove.h boxes.h shape.h tools.h unicode.h config.h | check_dir
|
remove.o: remove.c remove.h boxes.h detect.h shape.h tools.h unicode.h config.h | check_dir
|
||||||
shape.o: shape.c shape.h boxes.h bxstring.h tools.h config.h | check_dir
|
shape.o: shape.c shape.h boxes.h bxstring.h tools.h config.h | check_dir
|
||||||
tools.o: tools.c tools.h boxes.h regulex.h shape.h unicode.h config.h | check_dir
|
tools.o: tools.c tools.h boxes.h regulex.h shape.h unicode.h config.h | check_dir
|
||||||
unicode.o: unicode.c unicode.h boxes.h tools.h config.h | check_dir
|
unicode.o: unicode.c unicode.h boxes.h tools.h config.h | check_dir
|
||||||
|
@ -51,7 +51,8 @@ typedef struct {
|
|||||||
/** Number of invisible characters in the original string */
|
/** Number of invisible characters in the original string */
|
||||||
size_t num_chars_invisible;
|
size_t num_chars_invisible;
|
||||||
|
|
||||||
/** Number of trailing spaces in the original string */
|
/** Number of trailing spaces in the original string. In a line consisting only of spaces, this is zero, because
|
||||||
|
* the spaces would count towards the indent. */
|
||||||
size_t trailing;
|
size_t trailing;
|
||||||
|
|
||||||
/** Array of index values into `memory` of the first actual character (possibly invisible) of each visible
|
/** Array of index values into `memory` of the first actual character (possibly invisible) of each visible
|
||||||
|
33
src/detect.c
33
src/detect.c
@ -91,6 +91,7 @@ int design_is_mono(design_t *design)
|
|||||||
int comp_type_is_viable(comparison_t comp_type, int mono_input, int mono_design)
|
int comp_type_is_viable(comparison_t comp_type, int mono_input, int mono_design)
|
||||||
{
|
{
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
/* TODO What if a mono box was drawn around colored text? -> literal would be fine. Be less strict? */
|
||||||
if ((comp_type == literal && mono_input != mono_design)
|
if ((comp_type == literal && mono_input != mono_design)
|
||||||
|| (comp_type == ignore_invisible_input && (mono_input || !mono_design))
|
|| (comp_type == ignore_invisible_input && (mono_input || !mono_design))
|
||||||
|| (comp_type == ignore_invisible_shape && (!mono_input || mono_design))
|
|| (comp_type == ignore_invisible_shape && (!mono_input || mono_design))
|
||||||
@ -171,7 +172,8 @@ uint32_t *prepare_comp_shape(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t *prepare_comp_input(size_t input_line_idx, int trim_left, comparison_t comp_type, size_t offset_right)
|
uint32_t *prepare_comp_input(size_t input_line_idx, int trim_left, comparison_t comp_type, size_t offset_right,
|
||||||
|
size_t *out_indent, size_t *out_trailing)
|
||||||
{
|
{
|
||||||
if (input_line_idx >= input.num_lines) {
|
if (input_line_idx >= input.num_lines) {
|
||||||
bx_fprintf(stderr, "%s: prepare_comp_input(%d, %d, %s, %d): Index out of bounds\n", PROJECT,
|
bx_fprintf(stderr, "%s: prepare_comp_input(%d, %d, %s, %d): Index out of bounds\n", PROJECT,
|
||||||
@ -187,11 +189,20 @@ uint32_t *prepare_comp_input(size_t input_line_idx, int trim_left, comparison_t
|
|||||||
uint32_t *p = visible + input_line->num_chars_visible - input_line->trailing - offset_right;
|
uint32_t *p = visible + input_line->num_chars_visible - input_line->trailing - offset_right;
|
||||||
if (p >= visible) {
|
if (p >= visible) {
|
||||||
result = p;
|
result = p;
|
||||||
|
if (out_indent != NULL) {
|
||||||
|
*out_indent = BMAX(input_line->indent - (size_t) (p - visible), (size_t) 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
size_t ltrim = trim_left ? input_line->indent : 0;
|
size_t ltrim = trim_left ? input_line->indent : 0;
|
||||||
result = get_visible_text(input.lines + input_line_idx) + ltrim;
|
result = get_visible_text(input.lines + input_line_idx) + ltrim;
|
||||||
|
if (out_indent != NULL) {
|
||||||
|
*out_indent = trim_left ? 0 : input_line->indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (out_trailing != NULL) {
|
||||||
|
*out_trailing = input_line->trailing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -200,10 +211,20 @@ uint32_t *prepare_comp_input(size_t input_line_idx, int trim_left, comparison_t
|
|||||||
- offset_right;
|
- offset_right;
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
result = input_line->memory + idx;
|
result = input_line->memory + idx;
|
||||||
|
if (out_indent != NULL) {
|
||||||
|
*out_indent = BMAX(input_line->first_char[input_line->indent] - (size_t) idx, (size_t) 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result = trim_left ? bxs_unindent_ptr(input_line) : input_line->memory;
|
result = trim_left ? bxs_unindent_ptr(input_line) : input_line->memory;
|
||||||
|
if (out_indent != NULL) {
|
||||||
|
*out_indent = trim_left ? 0 : input_line->first_char[input_line->indent];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (out_trailing != NULL) {
|
||||||
|
*out_trailing = input_line->num_chars
|
||||||
|
- input_line->first_char[input_line->num_chars_visible - input_line->trailing];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -245,7 +266,7 @@ static size_t find_west_corner(design_t *current_design, comparison_t comp_type,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0);
|
uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0, NULL, NULL);
|
||||||
if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
|
if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
|
||||||
++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
|
++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
|
||||||
}
|
}
|
||||||
@ -295,7 +316,7 @@ static size_t find_east_corner(design_t *current_design, comparison_t comp_type,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *input_relevant = prepare_comp_input(a, 0, comp_type, length_relevant);
|
uint32_t *input_relevant = prepare_comp_input(a, 0, comp_type, length_relevant, NULL, NULL);
|
||||||
if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
|
if (u32_strncmp(input_relevant, shape_relevant, length_relevant) == 0) {
|
||||||
++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
|
++hits; /* CHECK more hit points for longer matches, or simple boxes might match too easily */
|
||||||
}
|
}
|
||||||
@ -345,8 +366,8 @@ static size_t find_horizontal_shape(design_t *current_design, comparison_t comp_
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *input_relevant = prepare_comp_input(a, 1, comp_type, 0); /* CHECK this eats blank NW corners */
|
uint32_t *input_relevant = prepare_comp_input(a, 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) {
|
||||||
@ -397,7 +418,7 @@ static size_t find_vertical_west(design_t *current_design, comparison_t comp_typ
|
|||||||
for (size_t k = empty[BTOP] ? 0 : current_design->shape[NW].height;
|
for (size_t k = empty[BTOP] ? 0 : current_design->shape[NW].height;
|
||||||
k < input.num_lines - (empty[BBOT] ? 0 : current_design->shape[SW].height); ++k)
|
k < input.num_lines - (empty[BBOT] ? 0 : current_design->shape[SW].height); ++k)
|
||||||
{
|
{
|
||||||
uint32_t *input_relevant = prepare_comp_input(k, 1, comp_type, 0);
|
uint32_t *input_relevant = prepare_comp_input(k, 1, comp_type, 0, NULL, NULL);
|
||||||
|
|
||||||
for (size_t j = 0; j < current_design->shape[vshape].height; ++j) {
|
for (size_t j = 0; j < current_design->shape[vshape].height; ++j) {
|
||||||
bxstr_t *shape_line = current_design->shape[vshape].mbcs[j];
|
bxstr_t *shape_line = current_design->shape[vshape].mbcs[j];
|
||||||
|
11
src/detect.h
11
src/detect.h
@ -41,7 +41,7 @@ typedef enum {
|
|||||||
} comparison_t;
|
} comparison_t;
|
||||||
|
|
||||||
/** The elements of `comparision_t` as strings for printing */
|
/** The elements of `comparision_t` as strings for printing */
|
||||||
char *comparison_name[];
|
extern char *comparison_name[];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,10 +94,17 @@ uint32_t *prepare_comp_shape(
|
|||||||
* @param offset_right `> 0`: the result pointer will point to the last `offset_right` non-blank characters (visible
|
* @param offset_right `> 0`: the result pointer will point to the last `offset_right` non-blank characters (visible
|
||||||
* or invisible) of the string; `== 0`: result pointer will point to start of string (possibly trimmed as
|
* or invisible) of the string; `== 0`: result pointer will point to start of string (possibly trimmed as
|
||||||
* per `trim_left`)
|
* per `trim_left`)
|
||||||
|
* @param out_indent pointer to a memory location where it is stored how many characters at the start of the result
|
||||||
|
* string are considered part of the indent, for example leading spaces, including any invisible characters.
|
||||||
|
* If NULL, it is ignored.
|
||||||
|
* @param out_trailing pointer to a memory location where it is stored how many characters at the end of the result
|
||||||
|
* string are considered trailing, for example trailing spaces, including any invisible characters. If NULL,
|
||||||
|
* it is ignored.
|
||||||
* @return the relevant part of the selected input line, in original memory (do not free this), or
|
* @return the relevant part of the selected input line, in original memory (do not free this), or
|
||||||
* NULL if `input_line_idx` out of bounds or `offset_right` too large
|
* NULL if `input_line_idx` out of bounds or `offset_right` too large
|
||||||
*/
|
*/
|
||||||
uint32_t *prepare_comp_input(size_t input_line_idx, int trim_left, comparison_t comp_type, size_t offset_right);
|
uint32_t *prepare_comp_input(size_t input_line_idx, int trim_left, comparison_t comp_type, size_t offset_right,
|
||||||
|
size_t *out_indent, size_t *out_trailing);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
1343
src/remove.c
1343
src/remove.c
File diff suppressed because it is too large
Load Diff
12
src/remove.h
12
src/remove.h
@ -21,7 +21,19 @@
|
|||||||
#define REMOVE_H
|
#define REMOVE_H
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove box from input.
|
||||||
|
* @return == 0: success;
|
||||||
|
* \!= 0: error
|
||||||
|
*/
|
||||||
int remove_box();
|
int remove_box();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output contents of input line list "as is" to standard output, except for removal of trailing spaces (trimming).
|
||||||
|
* The trimming is performed on the actual input lines, modifying them.
|
||||||
|
* @param trim_only only perform the trimming of trailing spaces, but do not output anything
|
||||||
|
*/
|
||||||
void output_input(const int trim_only);
|
void output_input(const int trim_only);
|
||||||
|
|
||||||
|
|
||||||
|
795
src/remove.old.c
Normal file
795
src/remove.old.c
Normal file
@ -0,0 +1,795 @@
|
|||||||
|
/*
|
||||||
|
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||||
|
* Copyright (c) 1999-2023 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 3, 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, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Box removal, i.e. the deletion of boxes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistr.h>
|
||||||
|
|
||||||
|
#include "detect.h"
|
||||||
|
#include "shape.h"
|
||||||
|
#include "boxes.h"
|
||||||
|
#include "tools.h"
|
||||||
|
#include "unicode.h"
|
||||||
|
#include "remove.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find positions of west and east box parts in line.
|
||||||
|
* @param line line to examine
|
||||||
|
* @param ws result parameter: west start as pointer to a character in `line->text->memory`
|
||||||
|
* @param we result parameter: west end as pointer to a character in `line->text->memory`
|
||||||
|
* @param es result parameter: east start as pointer to a character in `line->text->memory`
|
||||||
|
* @param ee result parameter: east end as pointer to a character in `line->text->memory`
|
||||||
|
* @return > 0: a match was found (ws etc. are set to indicate positions);
|
||||||
|
* == 0: no match was found;
|
||||||
|
* < 0: internal error (out of memory)
|
||||||
|
*/
|
||||||
|
static int best_match(const line_t *line, uint32_t **ws, uint32_t **we, uint32_t **es, uint32_t **ee)
|
||||||
|
{
|
||||||
|
size_t numw = 0; /* number of shape lines on west side */
|
||||||
|
size_t nume = 0; /* number of shape lines on east side */
|
||||||
|
size_t j; /* counts number of lines of all shapes tested */
|
||||||
|
size_t k; /* line counter within shape */
|
||||||
|
int w; /* shape counter */
|
||||||
|
sentry_t *cs; /* current shape */
|
||||||
|
uint32_t *s; /* duplicate of current shape part */
|
||||||
|
uint32_t *p; /* position found by u32_strstr() */
|
||||||
|
size_t cq; /* current quality */
|
||||||
|
uint32_t *q; /* space check rover */
|
||||||
|
size_t quality;
|
||||||
|
|
||||||
|
*ws = *we = *es = *ee = NULL;
|
||||||
|
|
||||||
|
numw = opt.design->shape[WNW].height;
|
||||||
|
numw += opt.design->shape[W].height;
|
||||||
|
numw += opt.design->shape[WSW].height;
|
||||||
|
|
||||||
|
nume = opt.design->shape[ENE].height;
|
||||||
|
nume += opt.design->shape[E].height;
|
||||||
|
nume += opt.design->shape[ESE].height;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf (stderr, "Number of WEST side shape lines: %d\n", (int) numw);
|
||||||
|
fprintf (stderr, "Number of EAST side shape lines: %d\n", (int) nume);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find match for WEST side
|
||||||
|
*/
|
||||||
|
if (!empty_side(opt.design->shape, BLEF)) {
|
||||||
|
quality = 0;
|
||||||
|
cs = opt.design->shape + WNW;
|
||||||
|
for (j = 0, k = 0, w = 3; j < numw; ++j, ++k) {
|
||||||
|
if (k == cs->height) {
|
||||||
|
k = 0;
|
||||||
|
cs = opt.design->shape + west_side[--w];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bxs_is_blank(cs->mbcs[k]) && !(quality == 0 && j == numw - 1)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = u32_strdup(cs->mbcs[k]->memory);
|
||||||
|
if (s == NULL) {
|
||||||
|
perror(PROJECT);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cq = cs->width;
|
||||||
|
|
||||||
|
do {
|
||||||
|
p = u32_strstr(line->text->memory, s);
|
||||||
|
if (p) {
|
||||||
|
q = p - 1;
|
||||||
|
while (q >= line->text->memory) {
|
||||||
|
if (*q-- != ' ') {
|
||||||
|
p = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!p && cq) {
|
||||||
|
if (*s == char_space) {
|
||||||
|
u32_move(s, s + 1, cq--);
|
||||||
|
} else if (s[cq - 1] == char_space) {
|
||||||
|
s[--cq] = char_nul;
|
||||||
|
} else {
|
||||||
|
cq = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (cq && !p);
|
||||||
|
|
||||||
|
if (cq == 0) {
|
||||||
|
BFREE (s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the current match is the best yet, adjust result values
|
||||||
|
*/
|
||||||
|
if (cq > quality) {
|
||||||
|
quality = cq;
|
||||||
|
*ws = p;
|
||||||
|
*we = p + cq;
|
||||||
|
}
|
||||||
|
|
||||||
|
BFREE (s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find match for EAST side
|
||||||
|
*/
|
||||||
|
if (!empty_side(opt.design->shape, BRIG)) {
|
||||||
|
quality = 0;
|
||||||
|
cs = opt.design->shape + ENE;
|
||||||
|
for (j = 0, k = 0, w = 1; j < nume; ++j, ++k) {
|
||||||
|
if (k == cs->height) {
|
||||||
|
k = 0;
|
||||||
|
cs = opt.design->shape + east_side[++w];
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
char *mbcs_temp = bxs_to_output(cs->mbcs[k]);
|
||||||
|
fprintf(stderr, "\nj %d, k %d, w %d, cs->chars[k] = \"%s\", cs->mbcs[k] = \"%s\"\n",
|
||||||
|
(int) j, (int) k, w, cs->chars[k] ? cs->chars[k] : "(null)", mbcs_temp);
|
||||||
|
BFREE(mbcs_temp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (bxs_is_blank(cs->mbcs[k])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = u32_strdup(cs->mbcs[k]->memory);
|
||||||
|
if (s == NULL) {
|
||||||
|
perror(PROJECT);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cq = cs->width;
|
||||||
|
|
||||||
|
do {
|
||||||
|
p = u32_strnrstr(line->text->memory, s, cq, 0);
|
||||||
|
if (p) {
|
||||||
|
q = p + cq;
|
||||||
|
while (*q) {
|
||||||
|
if (*q++ != ' ') {
|
||||||
|
p = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (p) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!p && cq) {
|
||||||
|
if (*s == ' ') {
|
||||||
|
u32_move(s, s + 1, cq--);
|
||||||
|
} else if (s[cq - 1] == ' ') {
|
||||||
|
s[--cq] = '\0';
|
||||||
|
} else {
|
||||||
|
cq = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (cq && !p);
|
||||||
|
|
||||||
|
if (cq == 0) {
|
||||||
|
BFREE (s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the current match is the best yet, adjust result values
|
||||||
|
*/
|
||||||
|
if (cq > quality) {
|
||||||
|
quality = cq;
|
||||||
|
*es = p;
|
||||||
|
*ee = p + cq;
|
||||||
|
}
|
||||||
|
|
||||||
|
BFREE (s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ws || *es ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int hmm(const int aside, const size_t follow,
|
||||||
|
const char *p, const char *ecs, const int cnt)
|
||||||
|
/*
|
||||||
|
* (horizontal middle match)
|
||||||
|
*
|
||||||
|
* aside box part to check (BTOP or BBOT)
|
||||||
|
* follow index of line number in shape spec to check
|
||||||
|
* p current check position
|
||||||
|
* ecs pointer to first char of east corner shape
|
||||||
|
* cnt current shape to check (0 == leftmost middle shape)
|
||||||
|
*
|
||||||
|
* Recursive helper function for detect_horiz(), uses backtracking
|
||||||
|
*
|
||||||
|
* RETURNS: == 0 success
|
||||||
|
* != 0 error
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int cmp;
|
||||||
|
sentry_t *cs;
|
||||||
|
shape_t sh;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "hmm (%s, %d, \'%c\', \'%c\', %d)\n",
|
||||||
|
aside == BTOP ? "BTOP" : "BBOT", (int) follow, p[0], *ecs, cnt);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (p > ecs) { /* last shape tried was too long */
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
sh = leftmost(aside, cnt);
|
||||||
|
if (sh == NUM_SHAPES) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cs = opt.design->shape + sh;
|
||||||
|
|
||||||
|
cmp = strncmp(p, cs->chars[follow], cs->width);
|
||||||
|
|
||||||
|
if (cmp == 0) {
|
||||||
|
if (p + cs->width == ecs) {
|
||||||
|
if (leftmost(aside, cnt + 1) == NUM_SHAPES) {
|
||||||
|
return 0; /* good! all clear, it matched */
|
||||||
|
} else {
|
||||||
|
return 3;
|
||||||
|
} /* didn't use all shapes to do it */
|
||||||
|
}
|
||||||
|
if (cs->elastic) {
|
||||||
|
rc = hmm(aside, follow, p + cs->width, ecs, cnt);
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf (stderr, "hmm returned %d\n", rc);
|
||||||
|
#endif
|
||||||
|
if (rc) {
|
||||||
|
rc = hmm(aside, follow, p + cs->width, ecs, cnt + 1);
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf (stderr, "hmm returned %d\n", rc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rc = hmm(aside, follow, p + cs->width, ecs, cnt + 1);
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf (stderr, "hmm returned %d\n", rc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
return 0; /* we're on the way back */
|
||||||
|
} else {
|
||||||
|
return 4;
|
||||||
|
} /* can't continue on this path */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 5; /* no match */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int detect_horiz(const int aside, size_t *hstart, size_t *hend)
|
||||||
|
/*
|
||||||
|
* Detect which part of the input belongs to the top/bottom of the box
|
||||||
|
*
|
||||||
|
* aside part of box to detect (BTOP or BBOT)
|
||||||
|
* hstart index of first line of detected box part (result)
|
||||||
|
* hend index of first line following detected box part (result)
|
||||||
|
*
|
||||||
|
* We assume the horizontal parts of the box to be in one piece, i.e. no
|
||||||
|
* blank lines inserted. Lines may be missing, though. Lines may not be
|
||||||
|
* duplicated. They may be shifted left and right by inserting whitespace,
|
||||||
|
* but whitespace which is part of the box must not have been deleted
|
||||||
|
* (unless it's because an entire box side is empty). Box part lines may
|
||||||
|
* even differ in length as long as each line is in itself a valid
|
||||||
|
* horizontal box line.
|
||||||
|
*
|
||||||
|
* RETURNS: == 0 success (hstart & hend are set)
|
||||||
|
* != 0 error
|
||||||
|
*
|
||||||
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
size_t follow; /* possible box line */
|
||||||
|
sentry_t *cs; /* current shape */
|
||||||
|
line_t *line; /* currently processed input line */
|
||||||
|
size_t lcnt; /* line counter */
|
||||||
|
char *p = NULL; /* middle line part scanner */
|
||||||
|
char *q; /* space check rover */
|
||||||
|
char *wcs = NULL; /* west corner shape position */
|
||||||
|
char *ecs = NULL; /* east corner shape position */
|
||||||
|
int mmok = 0; /* true if middle match was ok */
|
||||||
|
size_t mheight; /* regular height of box part */
|
||||||
|
int result_init = 0; /* true if hstart etc. was init. */
|
||||||
|
int nowside; /* true if west side is empty */
|
||||||
|
int goeast; /* no. of finds to ignore on right */
|
||||||
|
int gowest; /* set to request search start incr. */
|
||||||
|
|
||||||
|
*hstart = *hend = 0;
|
||||||
|
nowside = empty_side(opt.design->shape, BLEF);
|
||||||
|
|
||||||
|
mheight = opt.design->shape[sides[aside][0]].height;
|
||||||
|
if (aside == BTOP) {
|
||||||
|
follow = 0;
|
||||||
|
line = input.lines;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
follow = mheight - 1;
|
||||||
|
line = input.lines + input.num_lines - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (lcnt = 0; lcnt < mheight && lcnt < input.num_lines
|
||||||
|
&& line >= input.lines; ++lcnt) {
|
||||||
|
goeast = gowest = 0;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "----- Processing line index %2d -----------------------------------------------\n",
|
||||||
|
(int) (aside == BTOP ? lcnt : input.num_lines - lcnt - 1));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* Look for west corner shape
|
||||||
|
*/
|
||||||
|
if (!goeast) {
|
||||||
|
if (nowside) {
|
||||||
|
wcs = NULL;
|
||||||
|
if (gowest) {
|
||||||
|
gowest = 0;
|
||||||
|
if (*p == ' ' || *p == '\t') {
|
||||||
|
++p;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p = line->text->memory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cs = opt.design->shape + sides[aside][aside == BTOP ? 0 : SHAPES_PER_SIDE - 1];
|
||||||
|
if (gowest) {
|
||||||
|
gowest = 0;
|
||||||
|
wcs = strstr(wcs + 1, cs->chars[follow]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wcs = strstr(line->text, cs->chars[follow]);
|
||||||
|
}
|
||||||
|
if (wcs) {
|
||||||
|
for (q = wcs - 1; q >= line->text; --q) {
|
||||||
|
if (*q != ' ' && *q != '\t') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (q >= line->text) {
|
||||||
|
wcs = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!wcs) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = wcs + cs->width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Now, wcs is either NULL (if west side is empty) */
|
||||||
|
/* or not NULL (if west side is not empty). In any case, p */
|
||||||
|
/* points to where we start searching for the east corner. */
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (wcs) {
|
||||||
|
fprintf(stderr, "West corner shape matched at position %d.\n", (int) (wcs - line->text));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "West box side is empty.\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Look for east corner shape
|
||||||
|
*/
|
||||||
|
cs = opt.design->shape + sides[aside][aside == BTOP ? SHAPES_PER_SIDE - 1 : 0];
|
||||||
|
ecs = my_strnrstr(p, cs->chars[follow], cs->width, goeast);
|
||||||
|
if (ecs) {
|
||||||
|
for (q = ecs + cs->width; *q; ++q) {
|
||||||
|
if (*q != ' ' && *q != '\t') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*q) {
|
||||||
|
ecs = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ecs) {
|
||||||
|
if (goeast == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
goeast = 0;
|
||||||
|
gowest = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "East corner shape matched at position %d.\n", (int) (ecs - line->text));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if text between corner shapes is valid
|
||||||
|
*/
|
||||||
|
mmok = !hmm(aside, follow, p, ecs, 0);
|
||||||
|
if (!mmok) {
|
||||||
|
++goeast;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Text between corner shapes is %s.\n", mmok ? "VALID" : "NOT valid");
|
||||||
|
#endif
|
||||||
|
} while (!mmok);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Proceed to next line
|
||||||
|
*/
|
||||||
|
if (mmok) { /* match found */
|
||||||
|
if (!result_init) {
|
||||||
|
result_init = 1;
|
||||||
|
if (aside == BTOP) {
|
||||||
|
*hstart = lcnt;
|
||||||
|
} else {
|
||||||
|
*hend = (input.num_lines - lcnt - 1) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (aside == BTOP) {
|
||||||
|
*hend = lcnt + 1;
|
||||||
|
} else {
|
||||||
|
*hstart = input.num_lines - lcnt - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (result_init) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wcs = NULL;
|
||||||
|
ecs = NULL;
|
||||||
|
p = NULL;
|
||||||
|
mmok = 0;
|
||||||
|
|
||||||
|
if (aside == BTOP) {
|
||||||
|
++follow;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
--follow;
|
||||||
|
--line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result_init ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void add_spaces_to_line(line_t* line, const size_t n)
|
||||||
|
{
|
||||||
|
if (n == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bxs_append_spaces(line->text, n);
|
||||||
|
analyze_line_ascii(&input, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int remove_box()
|
||||||
|
{
|
||||||
|
size_t textstart = 0; /* index of 1st line of box body */
|
||||||
|
size_t textend = 0; /* index of 1st line of south side */
|
||||||
|
size_t boxstart = 0; /* index of 1st line of box */
|
||||||
|
size_t boxend = 0; /* index of 1st line trailing the box */
|
||||||
|
int m; /* true if a match was found */
|
||||||
|
size_t j; /* loop counter */
|
||||||
|
int did_something = 0; /* true if there was something to remove */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the user didn't specify a design to remove, autodetect it.
|
||||||
|
* Since this requires knowledge of all available designs, the entire
|
||||||
|
* config file had to be parsed (earlier).
|
||||||
|
*/
|
||||||
|
if (opt.design_choice_by_user == 0) {
|
||||||
|
design_t *tmp = autodetect_design();
|
||||||
|
if (tmp) {
|
||||||
|
opt.design = tmp;
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Design autodetection: Removing box of design \"%s\".\n", opt.design->name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "%s: Box design autodetection failed. Use -d option.\n", PROJECT);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make all lines the same length by adding trailing spaces (needed
|
||||||
|
* for recognition).
|
||||||
|
* Also append a number of spaces to ALL input lines. A greater number
|
||||||
|
* takes more space and time, but enables the correct removal of boxes
|
||||||
|
* whose east sides consist of lots of spaces (the given value). So we
|
||||||
|
* add a number of spaces equal to the east side width.
|
||||||
|
*/
|
||||||
|
const size_t normalized_len = input.maxline + opt.design->shape[NE].width;
|
||||||
|
for (j = 0; j < input.num_lines; ++j) {
|
||||||
|
add_spaces_to_line(input.lines + j, normalized_len - input.lines[j].text->num_columns);
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Normalized all lines to %d columns (maxline + east width).\n", (int) input.maxline);
|
||||||
|
print_input_lines(" (remove_box)");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 1: Try to find out how many lines belong to the top of the box
|
||||||
|
*/
|
||||||
|
boxstart = 0;
|
||||||
|
textstart = 0;
|
||||||
|
if (empty_side(opt.design->shape, BTOP)) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "----> Top box side is empty: boxstart == textstart == 0.\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
detect_horiz(BTOP, &boxstart, &textstart);
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "----> First line of box is %d, ", (int) boxstart);
|
||||||
|
fprintf(stderr, "first line of box body (text) is %d.\n", (int) textstart);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 2: Find out how many lines belong to the bottom of the box
|
||||||
|
*/
|
||||||
|
if (empty_side(opt.design->shape, BBOT)) {
|
||||||
|
textend = input.num_lines;
|
||||||
|
boxend = input.num_lines;
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "----> Bottom box side is empty: boxend == textend == %d.\n", (int) input.num_lines);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
textend = 0;
|
||||||
|
boxend = 0;
|
||||||
|
detect_horiz(BBOT, &textend, &boxend);
|
||||||
|
if (textend == 0 && boxend == 0) {
|
||||||
|
textend = input.num_lines;
|
||||||
|
boxend = input.num_lines;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "----> Last line of box body (text) is %d, ", (int) (textend - 1));
|
||||||
|
fprintf(stderr, "last line of box is %d.\n", (int) (boxend - 1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 3: Iterate over body lines, removing box sides where applicable
|
||||||
|
*/
|
||||||
|
for (j = textstart; j < textend; ++j) {
|
||||||
|
uint32_t *ws, *we, *es, *ee; /* west start & end, east start & end */
|
||||||
|
uint32_t *p;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Calling best_match() for line %d:\n", (int) j);
|
||||||
|
#endif
|
||||||
|
m = best_match(input.lines + j, &ws, &we, &es, &ee);
|
||||||
|
if (m < 0) {
|
||||||
|
fprintf(stderr, "%s: internal error\n", PROJECT);
|
||||||
|
return 1; /* internal error */
|
||||||
|
}
|
||||||
|
else if (m == 0) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "\033[00;33;01mline %2d: no side match\033[00m\n", (int) j);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "\033[00;33;01mline %2d: west: %d (\'%lc\') to %d (\'%lc\') [len %d]; "
|
||||||
|
"east: %d (\'%lc\') to %d (\'%lc\') [len %d]\033[00m\n", (int) j,
|
||||||
|
(int) (ws ? ws - input.lines[j].text->memory : 0), ws ? ws[0] : to_utf32('?'),
|
||||||
|
(int) (we ? we - input.lines[j].text->memory - 1 : 0), we ? we[-1] : to_utf32('?'),
|
||||||
|
(int) (ws && we ? (we - input.lines[j].text->memory - (ws - input.lines[j].text->memory)) : 0),
|
||||||
|
(int) (es ? es - input.lines[j].text->memory : 0), es ? es[0] : to_utf32('?'),
|
||||||
|
(int) (ee ? ee - input.lines[j].text->memory - 1 : 0), ee ? ee[-1] : to_utf32('?'),
|
||||||
|
(int) (es && ee ? (ee - input.lines[j].text->memory - (es - input.lines[j].text->memory)) : 0));
|
||||||
|
#endif
|
||||||
|
if (ws && we) {
|
||||||
|
did_something = 1;
|
||||||
|
for (p = ws; p < we; ++p) {
|
||||||
|
size_t idx = p - input.lines[j].text->memory; // TODO
|
||||||
|
*p = char_space; // TODO should only blank visible characters, or length of string would change
|
||||||
|
set_char_at(input.lines[j].mbtext, input.lines[j].posmap[idx], char_space);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (es && ee) {
|
||||||
|
for (p = es; p < ee; ++p) {
|
||||||
|
size_t idx = p - input.lines[j].text;
|
||||||
|
*p = ' ';
|
||||||
|
set_char_at(input.lines[j].mbtext, input.lines[j].posmap[idx], char_space);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove as many spaces from the left side of the line as the west side
|
||||||
|
* of the box was wide. Don't do it if we never removed anything from the
|
||||||
|
* west side. Don't harm the line's text if there aren't enough spaces.
|
||||||
|
*/
|
||||||
|
if (did_something) {
|
||||||
|
for (j = textstart; j < textend; ++j) {
|
||||||
|
size_t c;
|
||||||
|
size_t widz = opt.design->shape[NW].width + opt.design->padding[BLEF];
|
||||||
|
for (c = 0; c < widz; ++c) {
|
||||||
|
if (input.lines[j].text[c] != ' ') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if defined(DEBUG)
|
||||||
|
fprintf(stderr, "memmove(\"%s\", \"%s\", %d);\n",
|
||||||
|
input.lines[j].text, input.lines[j].text + c, (int) (input.lines[j].len - c + 1));
|
||||||
|
#endif
|
||||||
|
memmove(input.lines[j].text, input.lines[j].text + c,
|
||||||
|
input.lines[j].len - c + 1); /* +1 for zero byte */
|
||||||
|
input.lines[j].len -= c;
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
fprintf(stderr, "u32_move(\"%s\", \"%s\", %d); // posmap[c]=%d\n",
|
||||||
|
u32_strconv_to_output(input.lines[j].mbtext),
|
||||||
|
u32_strconv_to_output(input.lines[j].mbtext + input.lines[j].posmap[c]),
|
||||||
|
(int) (input.lines[j].num_chars - input.lines[j].posmap[c] + 1), (int) input.lines[j].posmap[c]);
|
||||||
|
#endif
|
||||||
|
u32_move(input.lines[j].mbtext, input.lines[j].mbtext + input.lines[j].posmap[c],
|
||||||
|
input.lines[j].num_chars - input.lines[j].posmap[c] + 1); /* +1 for zero byte */
|
||||||
|
input.lines[j].num_chars -= c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!did_something) {
|
||||||
|
fprintf(stderr, "There is nothing to remove (did_something == 0).\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Phase 4: Remove box top and body lines from input
|
||||||
|
*/
|
||||||
|
if (opt.killblank) {
|
||||||
|
while (empty_line(input.lines + textstart) && textstart < textend) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Killing leading blank line in box body.\n");
|
||||||
|
#endif
|
||||||
|
++textstart;
|
||||||
|
}
|
||||||
|
while (empty_line(input.lines + textend - 1) && textend > textstart) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "Killing trailing blank line in box body.\n");
|
||||||
|
#endif
|
||||||
|
--textend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textstart > boxstart) {
|
||||||
|
for (j = boxstart; j < textstart; ++j) BFREE (input.lines[j].text);
|
||||||
|
memmove(input.lines + boxstart, input.lines + textstart,
|
||||||
|
(input.num_lines - textstart) * sizeof(line_t));
|
||||||
|
input.num_lines -= textstart - boxstart;
|
||||||
|
textend -= textstart - boxstart;
|
||||||
|
boxend -= textstart - boxstart;
|
||||||
|
}
|
||||||
|
if (boxend > textend) {
|
||||||
|
for (j = textend; j < boxend; ++j) BFREE (input.lines[j].text);
|
||||||
|
if (boxend < input.num_lines) {
|
||||||
|
memmove(input.lines + textend, input.lines + boxend,
|
||||||
|
(input.num_lines - boxend) * sizeof(line_t));
|
||||||
|
}
|
||||||
|
input.num_lines -= boxend - textend;
|
||||||
|
}
|
||||||
|
input.maxline = 0;
|
||||||
|
for (j = 0; j < input.num_lines; ++j) {
|
||||||
|
if (input.lines[j].len - input.lines[j].invis > input.maxline) {
|
||||||
|
input.maxline = input.lines[j].len - input.lines[j].invis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memset(input.lines + input.num_lines, 0,
|
||||||
|
(BMAX (textstart - boxstart, (size_t) 0) + BMAX (boxend - textend, (size_t) 0)) * sizeof(line_t));
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
print_input_lines(" (remove_box) after box removal");
|
||||||
|
fprintf(stderr, "Number of lines shrunk by %d.\n",
|
||||||
|
(int) (BMAX (textstart - boxstart, (size_t) 0) + BMAX (boxend - textend, (size_t) 0)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0; /* all clear */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void output_input(const int trim_only)
|
||||||
|
{
|
||||||
|
size_t indent;
|
||||||
|
int ntabs, nspcs;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf(stderr, "output_input() - enter (trim_only=%d)\n", trim_only);
|
||||||
|
#endif
|
||||||
|
for (size_t j = 0; j < input.num_lines; ++j) {
|
||||||
|
if (input.lines[j].text == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bxstr_t *temp = bxs_rtrim(input.lines[j].text);
|
||||||
|
bxs_free(input.lines[j].text);
|
||||||
|
input.lines[j].text = temp;
|
||||||
|
if (trim_only) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *indentspc = NULL;
|
||||||
|
if (opt.tabexp == 'u') {
|
||||||
|
indent = input.lines[j].text->indent;
|
||||||
|
ntabs = indent / opt.tabstop;
|
||||||
|
nspcs = indent % opt.tabstop;
|
||||||
|
indentspc = (char *) malloc(ntabs + nspcs + 1);
|
||||||
|
if (indentspc == NULL) {
|
||||||
|
perror(PROJECT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(indentspc, (int) '\t', ntabs);
|
||||||
|
memset(indentspc + ntabs, (int) ' ', nspcs);
|
||||||
|
indentspc[ntabs + nspcs] = '\0';
|
||||||
|
}
|
||||||
|
else if (opt.tabexp == 'k') {
|
||||||
|
uint32_t *indent32 = tabbify_indent(j, NULL, input.indent);
|
||||||
|
indentspc = u32_strconv_to_output(indent32);
|
||||||
|
BFREE(indent32);
|
||||||
|
indent = input.indent;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
indentspc = (char *) strdup("");
|
||||||
|
indent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *outtext = u32_strconv_to_output(bxs_first_char_ptr(input.lines[j].text, indent));
|
||||||
|
fprintf(opt.outfile, "%s%s%s", indentspc, outtext,
|
||||||
|
(input.final_newline || j < input.num_lines - 1 ? opt.eol : ""));
|
||||||
|
BFREE(outtext);
|
||||||
|
BFREE(indentspc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* vim: set sw=4: */
|
@ -32,6 +32,7 @@ extern char *shape_name[];
|
|||||||
#define NUM_SHAPES 16
|
#define NUM_SHAPES 16
|
||||||
|
|
||||||
#define SHAPES_PER_SIDE 5
|
#define SHAPES_PER_SIDE 5
|
||||||
|
#define CORNERS_PER_SIDE 2
|
||||||
#define NUM_SIDES 4
|
#define NUM_SIDES 4
|
||||||
#define NUM_CORNERS 4
|
#define NUM_CORNERS 4
|
||||||
|
|
||||||
|
@ -350,7 +350,7 @@ uint32_t *u32_nspaces(const size_t n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO It seems skip is always 0, can we remove that parameter?
|
||||||
uint32_t *u32_strnrstr(const uint32_t *s1, const uint32_t *s2, const size_t s2_len, int skip)
|
uint32_t *u32_strnrstr(const uint32_t *s1, const uint32_t *s2, const size_t s2_len, int skip)
|
||||||
{
|
{
|
||||||
if (is_empty(s2)) {
|
if (is_empty(s2)) {
|
||||||
|
@ -249,8 +249,8 @@ uint32_t *u32_strnrstr(const uint32_t *s1, const uint32_t *s2, const size_t s2_l
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert `n` spaces at position `idx` into `s`. This modifies the given string.
|
* Insert `n` spaces at position `idx` into `*s`. This modifies the given string.
|
||||||
* @param s the string to modify
|
* @param s **pointer to** the string to modify. `*s` will be `realloc()`ed if needed.
|
||||||
* @param idx the position at which to insert. The character previously at this position will move to the right.
|
* @param idx the position at which to insert. The character previously at this position will move to the right.
|
||||||
* @param n the number of spaces to insert
|
* @param n the number of spaces to insert
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user