mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-01-19 04:18:12 +01:00
Initial revision
This commit is contained in:
parent
16ecdbb777
commit
79555dbf29
967
src/remove.c
Normal file
967
src/remove.c
Normal file
@ -0,0 +1,967 @@
|
||||
/*
|
||||
* File: remove.c
|
||||
* Project Main: boxes.c
|
||||
* Date created: June 23, 1999 (Wednesday, 20:59h)
|
||||
* Author: Thomas Jensen
|
||||
* tsjensen@stud.informatik.uni-erlangen.de
|
||||
* Version: $Id$
|
||||
* Language: ANSI C
|
||||
* World Wide Web: http://home.pages.de/~jensen/boxes/
|
||||
* Purpose: Box removal, i.e. the deletion of boxes
|
||||
* Remarks: ---
|
||||
*
|
||||
* Revision History:
|
||||
*
|
||||
* $Log$
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "shape.h"
|
||||
#include "boxes.h"
|
||||
#include "tools.h"
|
||||
#include "remove.h"
|
||||
|
||||
static const char rcsid_remove_c[] =
|
||||
"$Id$";
|
||||
|
||||
|
||||
|
||||
static int best_match (const line_t *line,
|
||||
char **ws, char **we, char **es, char **ee)
|
||||
/*
|
||||
* Find positions of west and east box parts in line.
|
||||
*
|
||||
* line line to examine
|
||||
* ws etc. result parameters (west start, west end, east start, east end)
|
||||
*
|
||||
* RETURNS: > 0 a match was found (ws etc are set to indicate positions)
|
||||
* == 0 no match was found
|
||||
* < 0 internal error (out of memory)
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
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 */
|
||||
char *s; /* duplicate of current shape part */
|
||||
char *p; /* position found by strstr */
|
||||
size_t cq; /* current quality */
|
||||
char *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", numw);
|
||||
fprintf (stderr, "Number of EAST side shape lines: %d\n", nume);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find match for WEST side
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
s = (char *) strdup (cs->chars[k]);
|
||||
if (s == NULL) {
|
||||
perror (PROJECT);
|
||||
return -1;
|
||||
}
|
||||
cq = cs->width;
|
||||
|
||||
do {
|
||||
p = strstr (line->text, s);
|
||||
if (p) {
|
||||
q = p-1;
|
||||
while (q >= line->text) {
|
||||
if (*q-- != ' ') {
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p)
|
||||
break;
|
||||
}
|
||||
if (!p && cq) {
|
||||
if (*s == ' ')
|
||||
memmove (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;
|
||||
*ws = p;
|
||||
*we = p + cq;
|
||||
}
|
||||
|
||||
BFREE (s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find match for EAST side
|
||||
*/
|
||||
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
|
||||
fprintf (stderr, "\nj %d, k %d, w %d, cs->chars[k] = \"%s\"\n",
|
||||
j, k, w, cs->chars[k]?cs->chars[k]:"(null)");
|
||||
#endif
|
||||
|
||||
s = (char *) strdup (cs->chars[k]);
|
||||
if (s == NULL) {
|
||||
perror (PROJECT);
|
||||
return -1;
|
||||
}
|
||||
cq = cs->width;
|
||||
|
||||
do {
|
||||
p = my_strnrstr (line->text, s, cq, 0);
|
||||
if (p) {
|
||||
q = p + cq;
|
||||
while (*q) {
|
||||
if (*q++ != ' ') {
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p)
|
||||
break;
|
||||
}
|
||||
if (!p && cq) {
|
||||
if (*s == ' ')
|
||||
memmove (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()
|
||||
*
|
||||
* 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", follow, p[0], *ecs, cnt);
|
||||
#endif
|
||||
|
||||
if (p > ecs) /* last shape tried was too long */
|
||||
return 2;
|
||||
|
||||
sh = leftmost (aside, cnt);
|
||||
if (sh == ANZ_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) == ANZ_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 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.
|
||||
* Unfortunately, they 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; /* index of currently proc.inp.line */
|
||||
char *p; /* middle line part scanner */
|
||||
char *q; /* space check rover */
|
||||
char *wcs = NULL; /* west corner shape position */
|
||||
char *ecs = NULL; /* east corner shape position */
|
||||
char *ecs_save; /* temp copy of ecs */
|
||||
int mmok; /* true if middle match was ok */
|
||||
size_t mheight; /* regular height of box part */
|
||||
int result_init = 0; /* true if hstart was set */
|
||||
int goeast, gowest;
|
||||
|
||||
*hstart = *hend = 0;
|
||||
|
||||
mheight = opt.design->shape[sides[aside][0]].height;
|
||||
if (aside == BTOP) {
|
||||
follow = 0;
|
||||
line=input.lines;
|
||||
}
|
||||
else {
|
||||
follow = mheight - 1;
|
||||
line = input.lines + input.anz_lines - 1;
|
||||
}
|
||||
|
||||
for (lcnt=0; lcnt<mheight && lcnt<input.anz_lines
|
||||
&& line >= input.lines; ++lcnt)
|
||||
{
|
||||
goeast = gowest = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "----- Processing line index %2d ----------"
|
||||
"-------------------------------------\n",
|
||||
aside == BTOP? lcnt: input.anz_lines - lcnt - 1);
|
||||
#endif
|
||||
|
||||
do {
|
||||
/*
|
||||
* Look for west corner shape
|
||||
*/
|
||||
cs = opt.design->shape + sides[aside][aside==BTOP?0:SHAPES_PER_SIDE-1];
|
||||
if (gowest) {
|
||||
wcs = strstr (wcs+1, cs->chars[follow]);
|
||||
gowest = 0;
|
||||
}
|
||||
else if (!wcs) {
|
||||
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;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (wcs)
|
||||
fprintf (stderr, "West corner shape matched at position %d.\n",
|
||||
wcs - line->text);
|
||||
else
|
||||
fprintf (stderr, "West corner shape not found.\n");
|
||||
#endif
|
||||
|
||||
p = wcs + cs->width;
|
||||
|
||||
/*
|
||||
* Look for east corner shape
|
||||
*/
|
||||
if (wcs) {
|
||||
cs = opt.design->shape + sides[aside][aside==BTOP?SHAPES_PER_SIDE-1:0];
|
||||
ecs_save = ecs;
|
||||
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) {
|
||||
gowest = 1;
|
||||
goeast = 0;
|
||||
ecs = ecs_save;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (ecs)
|
||||
fprintf (stderr, "East corner shape matched at position %d.\n",
|
||||
ecs-line->text);
|
||||
else
|
||||
fprintf (stderr, "East corner shape not found.\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if text between corner shapes is valid
|
||||
*/
|
||||
if (wcs && ecs) {
|
||||
mmok = !hmm (aside, follow, p, ecs, 0);
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Text between corner shapes is%s valid.\n",
|
||||
mmok? "": " NOT");
|
||||
#endif
|
||||
if (!mmok)
|
||||
++goeast;
|
||||
}
|
||||
|
||||
} while (!mmok && wcs);
|
||||
|
||||
/*
|
||||
* Proceed to next line
|
||||
*/
|
||||
if (wcs && ecs && mmok) { /* match found */
|
||||
if (!result_init) {
|
||||
result_init = 1;
|
||||
if (aside == BTOP)
|
||||
*hstart = lcnt;
|
||||
else
|
||||
*hend = (input.anz_lines - lcnt - 1) + 1;
|
||||
}
|
||||
if (aside == BTOP)
|
||||
*hend = lcnt + 1;
|
||||
else
|
||||
*hstart = input.anz_lines - lcnt - 1;
|
||||
}
|
||||
else {
|
||||
if (result_init)
|
||||
break;
|
||||
}
|
||||
wcs = NULL;
|
||||
ecs = NULL;
|
||||
|
||||
if (aside == BTOP) {
|
||||
++follow;
|
||||
++line;
|
||||
}
|
||||
else {
|
||||
--follow;
|
||||
--line;
|
||||
}
|
||||
}
|
||||
|
||||
return result_init? 0: 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static design_t *detect_design()
|
||||
/*
|
||||
* Autodetect design used by box in input.
|
||||
*
|
||||
* This requires knowledge about ALL designs, so the entire config file had
|
||||
* to be parsed at some earlier time.
|
||||
*
|
||||
* RETURNS: != NULL success, pointer to detected design
|
||||
* == NULL on error
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
design_t *d = designs; /* ptr to currently tested design */
|
||||
long hits; /* hit points of the current design */
|
||||
long maxhits = 0; /* maximum no. of hits so far */
|
||||
design_t *res = NULL; /* ptr to design with the most hits */
|
||||
int dcnt; /* design loop counter */
|
||||
shape_t scnt; /* shape loop counter */
|
||||
size_t j, k;
|
||||
char *p;
|
||||
char *s;
|
||||
line_t shpln; /* a line which is part of a shape */
|
||||
size_t a;
|
||||
int empty[ANZ_SIDES];
|
||||
|
||||
for (dcnt=0; dcnt<anz_designs; ++dcnt, ++d) {
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "CONSIDERING DESIGN ---- \"%s\" ---------------\n",
|
||||
d->name);
|
||||
#endif
|
||||
hits = 0;
|
||||
|
||||
for (j=0; j<ANZ_SIDES; ++j)
|
||||
empty[j] = empty_side (d, j);
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Empty sides: TOP %d, LEFT %d, BOTTOM %d, RIGHT %d\n",
|
||||
empty[BTOP], empty[BLEF], empty[BBOT], empty[BRIG]);
|
||||
#endif
|
||||
|
||||
for (scnt=0; scnt<ANZ_SHAPES; ++scnt) {
|
||||
|
||||
switch (scnt) {
|
||||
case NW: case SW:
|
||||
/*
|
||||
* Try and find west corner shapes. Every non-empty shape
|
||||
* line is searched for on every input line. A hit is
|
||||
* generated whenever a match is found.
|
||||
*/
|
||||
if (empty[BLEF] || (empty[BTOP] && scnt == NW)
|
||||
|| (empty[BBOT] && scnt == SW))
|
||||
break;
|
||||
for (j=0; j<d->shape[scnt].height; ++j) {
|
||||
shpln.text = d->shape[scnt].chars[j];
|
||||
shpln.len = d->shape[scnt].width;
|
||||
if (empty_line (&shpln))
|
||||
continue;
|
||||
for (s=shpln.text; *s==' ' || *s=='\t'; ++s);
|
||||
for (k=0; k<d->shape[scnt].height; ++k) {
|
||||
a = k;
|
||||
if (scnt == SW)
|
||||
a += input.anz_lines - d->shape[scnt].height;
|
||||
if (a >= input.anz_lines)
|
||||
break;
|
||||
for (p=input.lines[a].text; *p==' '||*p=='\t'; ++p);
|
||||
if (strncmp (p, s, shpln.len-(s-shpln.text)) == 0)
|
||||
++hits;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "After %s corner check:\t%ld hits.\n",
|
||||
shape_name[scnt], hits);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case NE: case SE:
|
||||
/*
|
||||
* Try and find east corner shapes. Every non-empty shape
|
||||
* line is searched for on every input line. A hit is
|
||||
* generated whenever a match is found.
|
||||
*/
|
||||
if (empty[BRIG] || (empty[BTOP] && scnt == NE)
|
||||
|| (empty[BBOT] && scnt == SE))
|
||||
break;
|
||||
for (j=0; j<d->shape[scnt].height; ++j) {
|
||||
shpln.text = d->shape[scnt].chars[j];
|
||||
shpln.len = d->shape[scnt].width;
|
||||
if (empty_line (&shpln))
|
||||
continue;
|
||||
for (s = shpln.text + shpln.len -1;
|
||||
(*s==' ' || *s=='\t') && shpln.len;
|
||||
--s, --(shpln.len));
|
||||
for (k=0; k<d->shape[scnt].height; ++k) {
|
||||
a = k;
|
||||
if (scnt == SE)
|
||||
a += input.anz_lines - d->shape[scnt].height;
|
||||
if (a >= input.anz_lines)
|
||||
break;
|
||||
for (p=input.lines[a].text + input.lines[a].len -1;
|
||||
p>=input.lines[a].text && (*p==' ' || *p=='\t');
|
||||
--p);
|
||||
p = p - shpln.len + 1;
|
||||
if (p < input.lines[a].text)
|
||||
continue;
|
||||
if (strncmp (p, shpln.text, shpln.len) == 0)
|
||||
++hits;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "After %s corner check:\t%ld hits.\n",
|
||||
shape_name[scnt], hits);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isempty (d->shape+scnt))
|
||||
continue;
|
||||
|
||||
if ((scnt >= NNW && scnt <= NNE)
|
||||
|| (scnt >= SSE && scnt <= SSW)) {
|
||||
/*
|
||||
* Try and find horizontal shapes between the box
|
||||
* corners. Every non-empty shape line is searched for
|
||||
* on every input line. Elastic shapes must occur
|
||||
* twice in an uninterrupted row to generate a hit.
|
||||
*/
|
||||
if ((scnt >= NNW && scnt <= NNE && empty[BTOP])
|
||||
|| (scnt >= SSE && scnt <= SSW && empty[BBOT])) {
|
||||
++hits;
|
||||
break; /* horizontal box part is empty */
|
||||
}
|
||||
for (j=0; j<d->shape[scnt].height; ++j) {
|
||||
shpln.text = d->shape[scnt].chars[j];
|
||||
shpln.len = d->shape[scnt].width;
|
||||
if (empty_line (&shpln))
|
||||
continue;
|
||||
for (k=0; k<d->shape[scnt].height; ++k) {
|
||||
a = k;
|
||||
if (scnt >= SSE && scnt <= SSW)
|
||||
a += input.anz_lines-d->shape[scnt].height;
|
||||
if (a >= input.anz_lines)
|
||||
break;
|
||||
for (p=input.lines[a].text;
|
||||
*p == ' ' || *p == '\t'; ++p);
|
||||
p += d->shape[NW].width;
|
||||
if (p-input.lines[a].text
|
||||
>= (long) input.lines[a].len)
|
||||
continue;
|
||||
p = strstr (p, shpln.text);
|
||||
if (p) {
|
||||
if (d->shape[scnt].elastic) {
|
||||
p += shpln.len;
|
||||
if (p-input.lines[a].text
|
||||
>= (long) input.lines[a].len)
|
||||
continue;
|
||||
if (!strncmp (p, shpln.text, shpln.len))
|
||||
++hits;
|
||||
}
|
||||
else {
|
||||
++hits;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((scnt >= ENE && scnt <= ESE)
|
||||
|| (scnt >= WSW && scnt <= WNW)) {
|
||||
/* handle later */
|
||||
break;
|
||||
}
|
||||
else {
|
||||
fprintf (stderr, "%s: internal error\n", PROJECT);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "After %s shape check:\t%ld hits.\n",
|
||||
shape_name[scnt], hits);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now iterate over all input lines except for potential top and
|
||||
* bottom box parts. Check if east and west line ends match a
|
||||
* non-empty shape line. If so, generate a hit.
|
||||
*/
|
||||
if (((empty[BTOP]? 0: d->shape[NW].height)
|
||||
+ (empty[BBOT]? 0: d->shape[SW].height)) < input.anz_lines)
|
||||
{
|
||||
for (k = empty[BTOP]? 0: d->shape[NW].height;
|
||||
k < input.anz_lines -(empty[BBOT]? 0: d->shape[SW].height);
|
||||
++k)
|
||||
{
|
||||
for (p=input.lines[k].text; *p==' ' || *p=='\t'; ++p);
|
||||
for (scnt=WSW; scnt<=WNW; ++scnt) {
|
||||
a = 0;
|
||||
if (isempty (d->shape + scnt))
|
||||
continue;
|
||||
for (j=0; j<d->shape[scnt].height; ++j) {
|
||||
shpln.text = d->shape[scnt].chars[j];
|
||||
shpln.len = d->shape[scnt].width;
|
||||
if (empty_line (&shpln))
|
||||
continue;
|
||||
for (s=shpln.text; *s==' ' || *s=='\t'; ++s);
|
||||
if (strncmp (p, s, shpln.len-(s-shpln.text)) == 0) {
|
||||
++hits;
|
||||
a = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (a)
|
||||
break;
|
||||
}
|
||||
|
||||
for (scnt=ENE; scnt<=ESE; ++scnt) {
|
||||
a = 0;
|
||||
if (isempty (d->shape + scnt))
|
||||
continue;
|
||||
for (j=0; j<d->shape[scnt].height; ++j) {
|
||||
shpln.text = d->shape[scnt].chars[j];
|
||||
shpln.len = d->shape[scnt].width;
|
||||
if (empty_line (&shpln))
|
||||
continue;
|
||||
for (p=input.lines[k].text + input.lines[k].len -1;
|
||||
p>=input.lines[a].text && (*p==' ' || *p=='\t');
|
||||
--p);
|
||||
for (s = shpln.text + shpln.len -1;
|
||||
(*s==' ' || *s=='\t') && shpln.len;
|
||||
--s, --(shpln.len));
|
||||
p = p - shpln.len + 1;
|
||||
if (strncmp (p, shpln.text, shpln.len) == 0) {
|
||||
++hits;
|
||||
a = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (a)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "After side checks:\t%ld hits.\n", hits);
|
||||
#endif
|
||||
|
||||
if (hits > maxhits) {
|
||||
maxhits = hits;
|
||||
res = d;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (res)
|
||||
fprintf (stderr, "CHOOSING \"%s\" design (%ld hits).\n",
|
||||
res->name, maxhits);
|
||||
else
|
||||
fprintf (stderr, "NO DESIGN FOUND WITH EVEN ONE HIT!\n");
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int remove_box()
|
||||
/*
|
||||
* foo
|
||||
*
|
||||
* RETURNS: == 0 success
|
||||
* != 0 error
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
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 = detect_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.
|
||||
*/
|
||||
input.maxline += opt.design->shape[NE].width;
|
||||
for (j=0; j<input.anz_lines; ++j) {
|
||||
input.lines[j].text = (char *)
|
||||
realloc (input.lines[j].text, input.maxline+1);
|
||||
if (input.lines[j].text == NULL) {
|
||||
perror (PROJECT);
|
||||
return 1;
|
||||
}
|
||||
memset (input.lines[j].text + input.lines[j].len, ' ',
|
||||
input.maxline - input.lines[j].len);
|
||||
input.lines[j].text[input.maxline] = '\0';
|
||||
input.lines[j].len = input.maxline;
|
||||
}
|
||||
|
||||
/*
|
||||
* Debugging Code: Display contents of input structure
|
||||
*/
|
||||
#if defined(DEBUG) && 1
|
||||
for (j=0; j<input.anz_lines; ++j) {
|
||||
fprintf (stderr, "%3d [%02d] \"%s\"\n", j, input.lines[j].len,
|
||||
input.lines[j].text);
|
||||
}
|
||||
fprintf (stderr, "\nLongest line: %d characters.\n", input.maxline);
|
||||
fprintf (stderr, " Indentation: %2d spaces.\n", input.indent);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Phase 1: Try to find out how many lines belong to the top of the box
|
||||
*/
|
||||
boxstart = 0;
|
||||
textstart = 0;
|
||||
detect_horiz (BTOP, &boxstart, &textstart);
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "----> First line of box is %d, ", boxstart);
|
||||
fprintf (stderr, "first line of box body (text) is %d.\n", textstart);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Phase 2: Find out how many lines belong to the bottom of the box
|
||||
*/
|
||||
textend = 0;
|
||||
boxend = 0;
|
||||
detect_horiz (BBOT, &textend, &boxend);
|
||||
if (textend == 0 && boxend == 0) {
|
||||
textend = input.anz_lines;
|
||||
boxend = input.anz_lines;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "----> Last line of box body (text) is %d, ", textend-1);
|
||||
fprintf (stderr, "last line of box is %d.\n", boxend-1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Phase 3: Iterate over body lines, removing box sides where applicable
|
||||
*/
|
||||
for (j=textstart; j<textend; ++j) {
|
||||
char *ws, *we, *es, *ee; /* west start & end, east start&end */
|
||||
char *p;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "Calling best_match() for line %d:\n", 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, "line %2d: no side match\n", j);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "\033[00;33mline %2d: west: %d (\'%c\') to "
|
||||
"%d (\'%c\') [len %d]; east: %d (\'%c\') to %d (\'%c\')"
|
||||
" [len %d]\033[00m\n", j,
|
||||
ws? ws-input.lines[j].text:0, ws?ws[0]:'?',
|
||||
we? we-input.lines[j].text-1:0, we?we[-1]:'?',
|
||||
ws&&we? (we-input.lines[j].text-(ws-input.lines[j].text)):0,
|
||||
es? es-input.lines[j].text:0, es?es[0]:'?',
|
||||
ee? ee-input.lines[j].text-1:0, ee?ee[-1]:'?',
|
||||
es&&ee? (ee-input.lines[j].text-(es-input.lines[j].text)):0);
|
||||
#endif
|
||||
if (ws && we) {
|
||||
did_something = 1;
|
||||
for (p=ws; p<we; ++p)
|
||||
*p = ' ';
|
||||
}
|
||||
if (es && ee) {
|
||||
for (p=es; p<ee; ++p)
|
||||
*p = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fprintf (stderr, "memmove (\"%s\", \"%s\", %d);\n",
|
||||
input.lines[j].text, input.lines[j].text + c,
|
||||
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;
|
||||
}
|
||||
}
|
||||
#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
|
||||
*/
|
||||
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.anz_lines-textstart)*sizeof(line_t));
|
||||
input.anz_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.anz_lines) {
|
||||
memmove (input.lines+textend, input.lines+boxend,
|
||||
(input.anz_lines-boxend)*sizeof(line_t));
|
||||
}
|
||||
input.anz_lines -= boxend - textend;
|
||||
}
|
||||
input.maxline = 0;
|
||||
for (j=0; j<input.anz_lines; ++j) {
|
||||
if (input.lines[j].len > input.maxline)
|
||||
input.maxline = input.lines[j].len;
|
||||
}
|
||||
memset (input.lines + input.anz_lines, 0,
|
||||
(BMAX (textstart - boxstart, 0) + BMAX (boxend - textend, 0)) *
|
||||
sizeof(line_t));
|
||||
|
||||
#ifdef DEBUG
|
||||
#if 0
|
||||
for (j=0; j<input.anz_lines; ++j) {
|
||||
fprintf (stderr, "%3d [%02d] \"%s\"\n", j, input.lines[j].len,
|
||||
input.lines[j].text);
|
||||
}
|
||||
#endif
|
||||
fprintf (stderr, "Number of lines shrunk by %d.\n",
|
||||
BMAX (textstart - boxstart, 0) + BMAX (boxend - textend, 0));
|
||||
#endif
|
||||
|
||||
return 0; /* all clear */
|
||||
}
|
||||
|
||||
|
||||
|
||||
void output_input()
|
||||
/*
|
||||
* Output contents of input line list "as is" to standard output, except
|
||||
* for removal of trailing spaces (trimming).
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
{
|
||||
size_t j;
|
||||
|
||||
for (j=0; j<input.anz_lines; ++j) {
|
||||
if (input.lines[j].text) {
|
||||
btrim (input.lines[j].text, &(input.lines[j].len));
|
||||
printf ("%s\n", input.lines[j].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*EOF*/ /* vim: set sw=4: */
|
28
src/remove.h
Normal file
28
src/remove.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* File: remove.h
|
||||
* Project Main: boxes.c
|
||||
* Date created: June 23, 1999 (Wednesday, 21:00h)
|
||||
* Author: Thomas Jensen
|
||||
* tsjensen@stud.informatik.uni-erlangen.de
|
||||
* Version: $Id$
|
||||
* Language: ANSI C
|
||||
* Purpose: Box removal, i.e. the deletion of boxes
|
||||
* Remarks: ---
|
||||
*
|
||||
* Revision History:
|
||||
*
|
||||
* $Log$
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
#ifndef REMOVE_H
|
||||
#define REMOVE_H
|
||||
|
||||
|
||||
int remove_box();
|
||||
void output_input();
|
||||
|
||||
|
||||
#endif /*REMOVE_H*/
|
||||
|
||||
/*EOF*/ /* vim: set cindent sw=4: */
|
Loading…
Reference in New Issue
Block a user