Commit 2c83d024 2c83d0247675ac08791401dc2b341d7f3f201830 by Sergey Poznyakoff

Improve locus tracker; provide a testsuite

* include/mailutils/locus.h (mu_locus_track_stat): New struct.
(mu_locus_tracker_stat): New proto.
(mu_locus_tracker_retreat): Change return type.
* libmailutils/locus/debug.c (mu_stream_vlprintf): Don't print
spurious \n.
(mu_lrange_debug): Fix incorrect call.
* libmailutils/locus/tracker.c (mu_locus_track_create): Allocate storage
for at least two lines of text.
(mu_locus_tracker_stat): New function.
(mu_locus_tracker_advance): Handle empty lines
(mu_locus_tracker_retreat): Add error handling.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add locktrack.
* libmailutils/tests/tracker.c: Rename to loctrack.c
* libmailutils/tests/testsuite.at: Add new testcase.
* libmailutils/tests/loctrack.at: New test case.
1 parent 4e7f5b5c
......@@ -19,6 +19,13 @@ struct mu_locus_range
typedef struct mu_locus_track *mu_locus_track_t;
struct mu_locus_track_stat
{
unsigned start_line;
size_t n_lines;
size_t n_chars;
};
int mu_ident_ref (char const *name, char const **refname);
int mu_ident_deref (char const *);
......@@ -48,7 +55,10 @@ size_t mu_locus_track_level (mu_locus_track_t trk);
void mu_locus_tracker_advance (struct mu_locus_track *trk,
struct mu_locus_range *loc,
char const *text, size_t leng);
void mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n);
int mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n);
int mu_locus_tracker_stat (struct mu_locus_track *trk,
struct mu_locus_track_stat *st);
void mu_stream_print_locus_range (mu_stream_t stream,
struct mu_locus_range const *loc);
......
......@@ -59,8 +59,7 @@ mu_stream_vlprintf (mu_stream_t stream,
{
mu_stream_print_locus_range (stream, loc);
mu_stream_write (stream, ": ", 2, NULL);
mu_stream_vprintf (mu_strerr, fmt, ap);
mu_stream_write (stream, "\n", 1, NULL);
mu_stream_vprintf (stream, fmt, ap);
}
void
......@@ -91,8 +90,9 @@ mu_lrange_debug (struct mu_locus_range const *loc,
}
va_start (ap, fmt);
mu_stream_lprintf (mu_strerr, loc, fmt, ap);
mu_stream_vlprintf (mu_strerr, loc, fmt, ap);
va_end (ap);
mu_stream_write (mu_strerr, "\n", 1, NULL);
if (rc == 0)
mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
......
......@@ -2,6 +2,7 @@
#include <errno.h>
#include <mailutils/types.h>
#include <mailutils/locus.h>
#include <mailutils/error.h>
struct mu_locus_track
{
......@@ -38,6 +39,8 @@ mu_locus_track_create (mu_locus_track_t *ret,
return rc;
}
if (max_lines < 2)
max_lines = 2;
trk->max_lines = max_lines;
trk->head = 0;
trk->level = 0;
......@@ -106,14 +109,34 @@ static inline unsigned *
pop (mu_locus_track_t trk)
{
if (trk->level == 0)
{
*cols_tos_ptr (trk) = 0;
return NULL; //FIXME
}
return NULL;
trk->level--;
return cols_tos_ptr (trk);
}
#ifndef SIZE_MAX
# define SIZE_MAX (~((size_t)0))
#endif
int
mu_locus_tracker_stat (struct mu_locus_track *trk,
struct mu_locus_track_stat *st)
{
size_t i, nch = 0;
for (i = 0; i <= trk->level; i++)
{
unsigned n = cols_peek (trk, i);
if (SIZE_MAX - nch < n)
return ERANGE;
nch += n;
}
st->start_line = trk->hline;
st->n_lines = trk->level;
st->n_chars = nch;
}
void
mu_locus_tracker_advance (struct mu_locus_track *trk,
struct mu_locus_range *loc,
......@@ -142,27 +165,44 @@ mu_locus_tracker_advance (struct mu_locus_track *trk,
}
else
{
/* Text ends with a newline. Keep the previos line number. */
loc->end.mu_line = trk->hline + trk->level - 1;
loc->end.mu_col = cols_peek (trk, trk->level - 1) - 1;
}
if (loc->end.mu_col + 1 == loc->beg.mu_col)
{
/* This happens if the previous line contained only newline. */
loc->beg.mu_col = loc->end.mu_col;
}
}
}
void
int
mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n)
{
unsigned *ptr;
struct mu_locus_track_stat st;
ptr = cols_tos_ptr (trk);
while (n--)
mu_locus_tracker_stat (trk, &st);
if (n > st.n_chars)
return ERANGE;
else
{
if (*ptr == 0)
unsigned *ptr = cols_tos_ptr (trk);
while (n--)
{
ptr = pop (trk);
if (!ptr)
break;
if (*ptr == 0)
{
ptr = pop (trk);
if (!ptr || *ptr == 0)
{
mu_error ("%s:%d: INTERNAL ERROR: out of pop back\n",
__FILE__, __LINE__);
return ERANGE;
}
}
--*ptr;
}
--*ptr;
}
return 0;
}
......
......@@ -19,6 +19,7 @@ fsfolder
globtest
imapio
listop
loctrack
logstr
mailcap
mimehdr
......@@ -34,7 +35,6 @@ strout
strtoc
tcli
tempfile
tracker
url-comp
url-parse
vexp
......
......@@ -54,6 +54,7 @@ noinst_PROGRAMS = \
globtest\
imapio\
listop\
loctrack\
logstr\
mailcap\
mimehdr\
......@@ -68,7 +69,6 @@ noinst_PROGRAMS = \
strout\
strtoc\
tempfile\
tracker\
tcli\
url-comp\
url-parse\
......@@ -107,6 +107,7 @@ TESTSUITE_AT = \
inline-comment.at\
linecon.at\
list.at\
loctrack.at\
logstr.at\
mailcap.at\
mimehdr.at\
......
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2017 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
AT_BANNER([Locus tracker])
m4_pushdef([TRACKTEST],[
AT_SETUP([$1])
AT_KEYWORDS([tracker $2])
AT_CHECK([loctrack liber $3 <<EOT
$4[]EOT
],
[0],
[$5],
[$6])
AT_CLEANUP
])
TRACKTEST([normal operation],[],[7],
[
agnosco
veteris\n
vestigia
flamme
\n
\n
Publius
Ovidius
Naso
],
[liber:1.1-7: agnosco
liber:1.8-14: veteris\n
liber:2.1-8: vestigia
liber:2.9-14: flamme
liber:2.14: \n
liber:3: \n
liber:4.1-7: Publius
liber:4.8-14: Ovidius
liber:4.15-18: Naso
])
TRACKTEST([retreat],[],[3],
[
agnosco
\-4
veteris
vestigia\n
flamme
\-8
Publius
],
[liber:1.1-7: agnosco
liber:1.4-10: veteris
liber:1.11-18: vestigia\n
liber:2.1-6: flamme
liber:1.18-24: Publius
])
TRACKTEST([retreat over several lines],[],[4],
[
one\n
two\n
three
\-11
four
],
[liber:1.1-3: one\n
liber:2.1-3: two\n
liber:3.1-5: three
liber:1.3-6: four
])
TRACKTEST([retreat to the beginning],[],[4],
[one\n
two\n
\-8
three
],
[liber:1.1-3: one\n
liber:2.1-3: two\n
liber:1.1-5: three
])
TRACKTEST([too big retreat],[],[2],
[one\n
two\n
\-10
three
],
[liber:1.1-3: one\n
liber:2.1-3: two\n
liber:3.1-5: three
],
[loctrack: retreat count too big
])
m4_popdef([TRACKTEST])
\ No newline at end of file
......@@ -33,22 +33,29 @@ main (int argc, char **argv)
char *tok;
n = mu_rtrim_class (buf, MU_CTYPE_SPACE);
if (buf[0] == '\\')
if (n == 0)
continue;
if (buf[0] == '\\' && buf[1] == '-')
{
long x = strtol (buf+1, &end, 10);
long x = strtol (buf+2, &end, 10);
if (*end || x == 0)
{
mu_error ("bad number");
continue;
}
mu_locus_tracker_retreat (trk, x);
rc = mu_locus_tracker_retreat (trk, x);
if (rc == ERANGE)
mu_error ("retreat count too big");
else if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_locus_tracker_retreat", buf+2,
rc);
}
else
{
mu_c_str_unescape (buf, "\\\n", "\\n", &tok);
mu_locus_tracker_advance (trk, &lr, tok, strlen (tok));
free (tok);
mu_lrange_debug (&lr, "%s", buf);
mu_stream_lprintf (mu_strout, &lr, "%s\n", buf);
}
}
return 0;
......
......@@ -212,3 +212,4 @@ m4_include([msgset.at])
m4_include([globtest.at])
m4_include([loctrack.at])
......