mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-04-25 00:18:23 +02:00
Some error message clean-up
Regular expression substituions on input text only if *drawing* a box, not if the box is to be removed (requires other substitutions, TODO). Added code for box design auto-detection when removing a box.
This commit is contained in:
parent
02b697659e
commit
9ebc20ebc0
329
src/boxes.c
329
src/boxes.c
@ -3,21 +3,42 @@
|
|||||||
* Date created: March 18, 1999 (Thursday, 15:09h)
|
* Date created: March 18, 1999 (Thursday, 15:09h)
|
||||||
* Author: Thomas Jensen
|
* Author: Thomas Jensen
|
||||||
* tsjensen@stud.informatik.uni-erlangen.de
|
* tsjensen@stud.informatik.uni-erlangen.de
|
||||||
* Version: $Id: boxes.c,v 1.11 1999/06/03 19:24:14 tsjensen Exp tsjensen $
|
* Version: $Id: boxes.c,v 1.12 1999/06/04 18:13:26 tsjensen Exp tsjensen $
|
||||||
* Language: ANSI C
|
* Language: ANSI C
|
||||||
* Platforms: sunos5/sparc, for now
|
* Platforms: sunos5/sparc, for now
|
||||||
* World Wide Web: http://home.pages.de/~jensen/boxes/
|
* World Wide Web: http://home.pages.de/~jensen/boxes/
|
||||||
* Purpose: Filter to draw boxes around input text.
|
* Purpose: Filter to draw boxes around input text (and remove it).
|
||||||
* Intended for use with vim(1).
|
* Intended for use with vim(1).
|
||||||
* Remarks: - This version is leaking memory. The sizes of the
|
*
|
||||||
* leaks do not depend on the number of lines
|
* Remarks: - This version is leaking a small bit of memory. The sizes
|
||||||
* processed, so the leaks don't matter as long as
|
* of the leaks do not depend on the number of lines
|
||||||
* this program is executed as a single process.
|
* processed, so the leaks don't matter as long as this
|
||||||
* - This is not a release.
|
* program is executed as a single process.
|
||||||
|
* - The decision to number box shapes in clockwise order was
|
||||||
|
* a major design mistake. Treatment of box parts of the
|
||||||
|
* same alignment (N-S and E-W) is usually combined in one
|
||||||
|
* function, which now must deal with the numbering being
|
||||||
|
* reversed all the time. This is nasty, but changing the
|
||||||
|
* shape order would pretty much mean a total rewrite of
|
||||||
|
* the code, so we'll have to live with it. :-(
|
||||||
|
* - All shapes defined in a box design must be used in any
|
||||||
|
* box of that design at least once. In other words, there
|
||||||
|
* must not be a shape which is defined in the config file
|
||||||
|
* but cannot be found in an actual box of that design.
|
||||||
|
* This sort of limits how small your boxes can get.
|
||||||
|
* However, in practice it is not a problem, because boxes
|
||||||
|
* which must be small usually consist of small shapes
|
||||||
|
* which can be packed pretty tightly anyway. And again,
|
||||||
|
* changing this would pretty much mean a total rewrite.
|
||||||
*
|
*
|
||||||
* Revision History:
|
* Revision History:
|
||||||
*
|
*
|
||||||
* $Log: boxes.c,v $
|
* $Log: boxes.c,v $
|
||||||
|
* Revision 1.12 1999/06/04 18:13:26 tsjensen
|
||||||
|
* Don't adjust indentation after removing a box unless something was
|
||||||
|
* removed on the west side
|
||||||
|
* East Padding made dynamic, i.e. dependant on the east side size
|
||||||
|
*
|
||||||
* Revision 1.11 1999/06/03 19:24:14 tsjensen
|
* Revision 1.11 1999/06/03 19:24:14 tsjensen
|
||||||
* a few fixes related to box removal (as expected)
|
* a few fixes related to box removal (as expected)
|
||||||
*
|
*
|
||||||
@ -34,21 +55,15 @@
|
|||||||
* Some minor fixes
|
* Some minor fixes
|
||||||
*
|
*
|
||||||
* Revision 1.7 1999/04/02 18:42:44 tsjensen
|
* Revision 1.7 1999/04/02 18:42:44 tsjensen
|
||||||
* ... still programming ...
|
|
||||||
* Added infile/outfile parameter code (pasted from tal, more or less)
|
* Added infile/outfile parameter code (pasted from tal, more or less)
|
||||||
* Added code to remove trailing spaces from output lines
|
* Added code to remove trailing spaces from output lines
|
||||||
*
|
*
|
||||||
* Revision 1.6 1999/04/01 17:26:18 tsjensen
|
* Revision 1.6 1999/04/01 17:26:18 tsjensen
|
||||||
* ... still programming ...
|
|
||||||
* Some bug fixes
|
* Some bug fixes
|
||||||
* Added size option (-s)
|
* Added size option (-s)
|
||||||
* Added Alignment Option (-a)
|
* Added Alignment Option (-a)
|
||||||
* It seems actually usable for drawing boxes :-)
|
* It seems actually usable for drawing boxes :-)
|
||||||
*
|
*
|
||||||
* Revision 1.5 1999/03/31 17:34:21 tsjensen
|
|
||||||
* ... still programming ...
|
|
||||||
* (some bug fixes and restructuring)
|
|
||||||
*
|
|
||||||
* Revision 1.4 1999/03/30 13:30:19 tsjensen
|
* Revision 1.4 1999/03/30 13:30:19 tsjensen
|
||||||
* Added minimum width/height for a design. Fixed screwed tiny boxes.
|
* Added minimum width/height for a design. Fixed screwed tiny boxes.
|
||||||
* Did not handle zero input.
|
* Did not handle zero input.
|
||||||
@ -57,9 +72,6 @@
|
|||||||
* ... still programming ...
|
* ... still programming ...
|
||||||
* (removed setlocale() call and locale.h include)
|
* (removed setlocale() call and locale.h include)
|
||||||
*
|
*
|
||||||
* Revision 1.2 1999/03/19 17:44:47 tsjensen
|
|
||||||
* ... still programming ...
|
|
||||||
*
|
|
||||||
* Revision 1.1 1999/03/18 15:09:17 tsjensen
|
* Revision 1.1 1999/03/18 15:09:17 tsjensen
|
||||||
* Initial revision
|
* Initial revision
|
||||||
*
|
*
|
||||||
@ -86,7 +98,7 @@ extern int optind, opterr, optopt; /* for getopt() */
|
|||||||
|
|
||||||
|
|
||||||
static const char rcsid_boxes_c[] =
|
static const char rcsid_boxes_c[] =
|
||||||
"$Id: boxes.c,v 1.11 1999/06/03 19:24:14 tsjensen Exp tsjensen $";
|
"$Id: boxes.c,v 1.12 1999/06/04 18:13:26 tsjensen Exp tsjensen $";
|
||||||
|
|
||||||
extern FILE *yyin; /* lex input file */
|
extern FILE *yyin; /* lex input file */
|
||||||
|
|
||||||
@ -928,6 +940,7 @@ int read_all_input()
|
|||||||
/*
|
/*
|
||||||
* Apply regular expression substitutions to line
|
* Apply regular expression substitutions to line
|
||||||
*/
|
*/
|
||||||
|
if (opt.r == 0) {
|
||||||
for (i=0; i<opt.design->anz_reprules; ++i) {
|
for (i=0; i<opt.design->anz_reprules; ++i) {
|
||||||
opt.design->current_reprule = opt.design->reprules + i;
|
opt.design->current_reprule = opt.design->reprules + i;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -962,6 +975,7 @@ int read_all_input()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
opt.design->current_reprule = NULL;
|
opt.design->current_reprule = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update length of longest line
|
* Update length of longest line
|
||||||
@ -2478,10 +2492,253 @@ int detect_horiz (const int aside, size_t *hstart, size_t *hend)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
long hits;
|
||||||
|
long maxhits = 0;
|
||||||
|
design_t *res = NULL;
|
||||||
|
int dcnt;
|
||||||
|
shape_t scnt;
|
||||||
|
size_t j, k;
|
||||||
|
char *p;
|
||||||
|
char *s;
|
||||||
|
line_t shpln;
|
||||||
|
size_t a;
|
||||||
|
|
||||||
|
for (dcnt=0; dcnt<anz_designs; ++dcnt, ++d) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
fprintf (stderr, "CONSIDERING DESIGN ---- \"%s\" ---------------\n",
|
||||||
|
d->name);
|
||||||
|
#endif
|
||||||
|
hits = 0;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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 (d->shape[NW].height + d->shape[SW].height < input.anz_lines) {
|
||||||
|
for (k=d->shape[NW].height; k<input.anz_lines-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()
|
int remove_box()
|
||||||
/*
|
/*
|
||||||
* foo
|
* foo
|
||||||
*
|
*
|
||||||
|
* RETURNS: == 0 success
|
||||||
|
* != 0 error
|
||||||
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
@ -2499,17 +2756,29 @@ int remove_box()
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the user didn't specify a design to remove, autodetect it.
|
* 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) {
|
if (opt.design_choice_by_user == 0) {
|
||||||
/* TODO */
|
design_t *tmp = detect_design();
|
||||||
fprintf (stderr, "%s: Can\'t autodetect designs yet. Use -d.\n",
|
if (tmp) {
|
||||||
PROJECT);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add trailing spaces to input lines (needed for recognition)
|
* Make all lines the same length by adding trailing spaces (needed
|
||||||
* Also append a number of spaces to all input lines. A greater number
|
* 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
|
* 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
|
* whose east sides consist of lots of spaces (the given value). So we
|
||||||
* add a number of spaces equal to the east side width.
|
* add a number of spaces equal to the east side width.
|
||||||
@ -2575,8 +2844,10 @@ int remove_box()
|
|||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
m = best_match (input.lines+j, &ws, &we, &es, &ee);
|
m = best_match (input.lines+j, &ws, &we, &es, &ee);
|
||||||
if (m < 0)
|
if (m < 0) {
|
||||||
|
fprintf (stderr, "%s: internal error\n", PROJECT);
|
||||||
return 1; /* internal error */
|
return 1; /* internal error */
|
||||||
|
}
|
||||||
if (m == 0) {
|
if (m == 0) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf (stderr, "line %2d: no side match\n", j);
|
fprintf (stderr, "line %2d: no side match\n", j);
|
||||||
@ -2622,6 +2893,11 @@ int remove_box()
|
|||||||
input.lines[j].len - c);
|
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
|
* Phase 4: Remove box top and body lines from input
|
||||||
@ -2783,13 +3059,12 @@ int main (int argc, char *argv[])
|
|||||||
|
|
||||||
if (opt.r) {
|
if (opt.r) {
|
||||||
rc = remove_box();
|
rc = remove_box();
|
||||||
if (rc) {
|
if (rc == 0) {
|
||||||
perror (PROJECT);
|
|
||||||
exit (EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
output_input();
|
output_input();
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf (stderr, "Generating Box ...\n");
|
fprintf (stderr, "Generating Box ...\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user