Commit 7bca245a 7bca245a054a58c7aaf889243fcacd73a5bd0982 by Sergey Poznyakoff

Begin implementing liblocus

Liblocus is a part of libmailutils that will provide functions for
manipulating source file locations, for use in lexers, grammars, etc.
This will expand the functionality of the mu_locus type and logstreams.

* configure.ac: add libmailutils/locus/
* include/mailutils/assoc.h (mu_assoc_install_ref2): New proto.
* libmailutils/base/assoc.c (mu_assoc_install_ref2): New entry point.
* libmailutils/base/copyfile.c (copy_regular_file): Add typecasts.
* libmailutils/Makefile.am: Build liblocus
* libmailutils/locus/Makefile.am: New file.
* libmailutils/locus/debug.c: New file.
* libmailutils/locus/ident.c: New file.
* libmailutils/locus/tracker.c: New file.
* libmailutils/tests/Makefile.am: New file.
* libmailutils/tests/tracker.c: New file.
1 parent 66da33c3
......@@ -1495,6 +1495,7 @@ AC_CONFIG_FILES([
libmailutils/filter/Makefile
libmailutils/imapio/Makefile
libmailutils/list/Makefile
libmailutils/locus/Makefile
libmailutils/mailbox/Makefile
libmailutils/mailer/Makefile
libmailutils/mime/Makefile
......
......@@ -37,6 +37,8 @@ int mu_assoc_install (mu_assoc_t assoc, const char *name, void *value);
int mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr);
int mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval);
int mu_assoc_install_ref2 (mu_assoc_t assoc, const char *name,
void *ret_val, const char **ret_name);
int mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator);
int mu_assoc_remove (mu_assoc_t assoc, const char *name);
......
#ifndef _MAILUTILS_LOCUS_H
#define _MAILUTILS_LOCUS_H
#include <string.h>
struct mu_locus_point
{
char const *mu_file;
unsigned mu_line;
unsigned mu_col;
};
struct mu_locus_range
{
struct mu_locus_point beg;
struct mu_locus_point end;
};
typedef struct mu_locus_track *mu_locus_track_t;
int mu_ident_ref (char const *name, char const **refname);
int mu_ident_deref (char const *);
static inline int
mu_locus_point_same_file (struct mu_locus_point const *a,
struct mu_locus_point const *b)
{
return a->mu_file == b->mu_file
|| (a->mu_file && b->mu_file && strcmp(a->mu_file, b->mu_file) == 0);
}
static inline int
mu_locus_point_same_line (struct mu_locus_point const *a,
struct mu_locus_point const *b)
{
return mu_locus_point_same_file (a, b) && a->mu_line == b->mu_line;
}
void mu_lrange_debug (struct mu_locus_range const *loc,
char const *fmt, ...);
int mu_locus_track_create (mu_locus_track_t *ret,
char const *file_name, size_t max_lines);
void mu_locus_track_free (mu_locus_track_t trk);
void mu_locus_track_destroy (mu_locus_track_t *trk);
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);
#endif
#define YYLTYPE struct mu_locus_range
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
{ \
if (N) \
{ \
(Current).beg = YYRHSLOC(Rhs, 1).beg; \
(Current).end = YYRHSLOC(Rhs, N).end; \
} \
else \
{ \
(Current).beg = YYRHSLOC(Rhs, 0).end; \
(Current).end = (Current).beg; \
} \
} while (0)
#define YY_LOCATION_PRINT(File, Loc) \
do \
{ \
if (!mu_locus_point_same_file (&(Loc).beg, &(Loc).end)) \
fprintf (File, "%s:%u.%u-%s:%u.%u", \
(Loc).beg.mu_file, \
(Loc).beg.mu_line, (Loc).beg.mu_col, \
(Loc).end.mu_file, \
(Loc).end.mu_line, (Loc).end.mu_col); \
else if ((Loc).beg.mu_line != (Loc).end.mu_line) \
fprintf (File, "%s:%u.%u-%u.%u", \
(Loc).beg.mu_file, \
(Loc).beg.mu_line, (Loc).beg.mu_col, \
(Loc).end.mu_line, (Loc).end.mu_col); \
else if ((Loc).beg.mu_col != (Loc).end.mu_col) \
fprintf (File, "%s:%u.%u-%u", \
(Loc).beg.mu_file, \
(Loc).beg.mu_line, (Loc).beg.mu_col, \
(Loc).end.mu_col); \
else \
fprintf (File, "%s:%u.%u", \
(Loc).beg.mu_file, \
(Loc).beg.mu_line, (Loc).beg.mu_col); \
} while (0)
......@@ -18,7 +18,7 @@
SUBDIRS = \
auth base address list sockaddr cidr cfg cli diag\
filter mailbox mailer mime msgset opt server string stream stdstream\
filter locus mailbox mailer mime msgset opt server string stream stdstream\
property url imapio datetime . tests
lib_LTLIBRARIES = libmailutils.la
......@@ -39,6 +39,7 @@ libmailutils_la_LIBADD = \
filter/libfilter.la\
imapio/libimapio.la\
list/liblist.la\
locus/liblocus.la\
mailbox/libmailbox.la\
mailer/libmailer.la\
mime/libmime.la\
......
......@@ -387,7 +387,9 @@ mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr)
}
int
mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval)
mu_assoc_install_ref2 (mu_assoc_t assoc, const char *name,
void *ret_val,
const char **ret_name)
{
int rc;
int inst;
......@@ -425,11 +427,20 @@ mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval)
assoc_elem_link (assoc, idx);
}
*(void**)pval = &assoc->tab[idx]->data;
*(void**)ret_val = &assoc->tab[idx]->data;
if (ret_name)
*ret_name = assoc->tab[idx]->name;
return inst ? 0 : MU_ERR_EXISTS;
}
int
mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval)
{
return mu_assoc_install_ref2 (assoc, name, pval, NULL);
}
int
mu_assoc_remove (mu_assoc_t assoc, const char *name)
{
int rc;
......
......@@ -163,7 +163,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags,
rc = mu_stream_ioctl (dst, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, trans);
if (rc == 0)
{
if (fchmod ((int) trans[0], mode))
if (fchmod ((int) (intptr_t) trans[0], mode))
{
mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR,
(_("%s: cannot chmod: %s"),
......@@ -193,7 +193,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags,
if (gid != -1)
{
if (fchown ((int) trans[0], uid, gid))
if (fchown ((int) (intptr_t) trans[0], uid, gid))
{
mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR,
(_("%s: cannot chown to %lu.%lu: %s"),
......
# GNU Mailutils -- a suite of utilities for electronic mail
# Copyright (C) 2017 Free Software Foundation, Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General
# Public License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
noinst_LTLIBRARIES = liblocus.la
liblocus_la_SOURCES = \
ident.c\
debug.c\
tracker.c
AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
#include <stdlib.h>
#include <stdarg.h>
#include <mailutils/types.h>
#include <mailutils/locus.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/diag.h>
#include <mailutils/stream.h>
#include <mailutils/stdstream.h>
void
mu_lrange_debug (struct mu_locus_range const *loc,
char const *fmt, ...)
{
va_list ap;
int rc, mode;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_GET_MODE, &mode);
if (rc == 0)
{
int new_mode = mode & ~MU_LOGMODE_LOCUS;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_MODE, &new_mode);
}
if (loc->beg.mu_col == 0)
mu_debug_log_begin ("%s:%u", loc->beg.mu_file, loc->beg.mu_line);
else if (!mu_locus_point_same_file (&loc->beg, &loc->end))
mu_debug_log_begin ("%s:%u.%u-%s:%u.%u",
loc->beg.mu_file,
loc->beg.mu_line, loc->beg.mu_col,
loc->end.mu_file,
loc->end.mu_line, loc->end.mu_col);
else if (loc->beg.mu_line != loc->end.mu_line)
mu_debug_log_begin ("%s:%u.%u-%u.%u",
loc->beg.mu_file,
loc->beg.mu_line, loc->beg.mu_col,
loc->end.mu_line, loc->end.mu_col);
else if (loc->beg.mu_col != loc->end.mu_col)
mu_debug_log_begin ("%s:%u.%u-%u",
loc->beg.mu_file,
loc->beg.mu_line, loc->beg.mu_col,
loc->end.mu_col);
else
mu_debug_log_begin ("%s:%u.%u",
loc->beg.mu_file,
loc->beg.mu_line, loc->beg.mu_col);
mu_stream_write (mu_strerr, ": ", 2, NULL);
va_start (ap, fmt);
mu_stream_vprintf (mu_strerr, fmt, ap);
va_end (ap);
mu_debug_log_nl ();
if (rc == 0)
mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
}
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/assoc.h>
#include <mailutils/locus.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/diag.h>
#include <mailutils/list.h>
struct mu_ident_ref
{
size_t count;
};
static mu_assoc_t nametab;
int
mu_ident_ref (char const *name, char const **refname)
{
int rc;
struct mu_ident_ref *ref, **refptr;
if (!name)
return EINVAL;
if (!refname)
return MU_ERR_OUT_PTR_NULL;
if (!nametab)
{
rc = mu_assoc_create (&nametab, 0);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_create", NULL, rc);
return rc;
}
mu_assoc_set_destroy_item (nametab, mu_list_free_item);
}
rc = mu_assoc_install_ref2 (nametab, name, &refptr, refname);
switch (rc)
{
case 0:
ref = malloc (sizeof *ref);
if (!ref)
{
rc = errno;
mu_assoc_remove (nametab, name);
return rc;
}
ref->count = 0;
break;
case MU_ERR_EXISTS:
ref = *refptr;
break;
default:
mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_install_ref2", name, rc);
return rc;
}
ref->count++;
return 0;
}
int
mu_ident_deref (char const *name)
{
struct mu_ident_ref *ref;
int rc;
if (!name)
return EINVAL;
if (!nametab)
return 0;
rc = mu_assoc_lookup (nametab, name, &ref);
switch (rc)
{
case 0:
if (--ref->count == 0)
mu_assoc_remove (nametab, name);
break;
case MU_ERR_NOENT:
break;
default:
mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_lookup", name, rc);
return rc;
}
return 0;
}
#include <stdlib.h>
#include <errno.h>
#include <mailutils/types.h>
#include <mailutils/locus.h>
struct mu_locus_track
{
char const *file_name; /* Name of the source file */
size_t max_lines; /* Max. number of lines history kept by tracker */
size_t head; /* Bottom of stack */
size_t level; /* Number of elements on stack */
unsigned hline; /* Number of line corresponding to cols[head] */
unsigned *cols; /* Cyclic stack */
};
int
mu_locus_track_create (mu_locus_track_t *ret,
char const *file_name, size_t max_lines)
{
int rc;
struct mu_locus_track *trk;
trk = malloc (sizeof *trk);
if (!trk)
return errno;
trk->cols = calloc (max_lines, sizeof (trk->cols[0]));
if (!trk->cols)
{
rc = errno;
free (trk);
return rc;
}
rc = mu_ident_ref (file_name, &trk->file_name);
if (rc)
{
free (trk->cols);
free (trk);
return rc;
}
trk->max_lines = max_lines;
trk->head = 0;
trk->level = 0;
trk->hline = 1;
trk->cols[0] = 0;
*ret = trk;
return 0;
}
void
mu_locus_track_free (mu_locus_track_t trk)
{
if (trk)
{
mu_ident_deref (trk->file_name);
free (trk->cols);
free (trk);
}
}
void
mu_locus_track_destroy (mu_locus_track_t *trk)
{
if (trk)
{
mu_locus_track_free (*trk);
*trk = NULL;
}
}
size_t
mu_locus_track_level (mu_locus_track_t trk)
{
return trk->level;
}
static inline unsigned *
cols_tos_ptr (mu_locus_track_t trk)
{
return &trk->cols[(trk->head + trk->level) % trk->max_lines];
}
static inline unsigned
cols_peek (mu_locus_track_t trk, size_t n)
{
return trk->cols[(trk->head + n) % trk->max_lines];
}
static inline unsigned *
push (mu_locus_track_t trk)
{
unsigned *ptr;
if (trk->level == trk->max_lines)
{
trk->head++;
trk->hline++;
}
else
trk->level++;
*(ptr = cols_tos_ptr (trk)) = 0;
return ptr;
}
static inline unsigned *
pop (mu_locus_track_t trk)
{
if (trk->level == 0)
{
*cols_tos_ptr (trk) = 0;
return NULL; //FIXME
}
trk->level--;
return cols_tos_ptr (trk);
}
void
mu_locus_tracker_advance (struct mu_locus_track *trk,
struct mu_locus_range *loc,
char const *text, size_t leng)
{
unsigned *ptr;
if (text == NULL || leng == 0)
return;
loc->beg.mu_file = loc->end.mu_file = trk->file_name;
loc->beg.mu_line = trk->hline + trk->level;
ptr = cols_tos_ptr (trk);
loc->beg.mu_col = *ptr + 1;
while (leng--)
{
(*ptr)++;
if (*text == '\n')
ptr = push (trk);
text++;
}
if (*ptr)
{
loc->end.mu_line = trk->hline + trk->level;
loc->end.mu_col = *ptr;
}
else
{
loc->end.mu_line = trk->hline + trk->level - 1;
loc->end.mu_col = cols_peek (trk, trk->level - 1) - 1;
}
}
void
mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n)
{
unsigned *ptr;
ptr = cols_tos_ptr (trk);
while (n--)
{
if (*ptr == 0)
{
ptr = pop (trk);
if (!ptr)
break;
}
--*ptr;
}
}
......@@ -33,6 +33,7 @@ strout
strtoc
tcli
tempfile
tracker
url-comp
url-parse
vexp
......
......@@ -67,6 +67,7 @@ noinst_PROGRAMS = \
strout\
strtoc\
tempfile\
tracker\
tcli\
url-comp\
url-parse\
......
#include <mailutils/mailutils.h>
#include <mailutils/locus.h>
int
main (int argc, char **argv)
{
unsigned long max_lines;
char *end;
mu_locus_track_t trk;
int rc;
char *buf = NULL;
size_t size, n;
mu_set_program_name (argv[0]);
mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
if (argc != 3)
{
mu_error ("usage: %s FILE LINES", mu_program_name);
return 1;
}
max_lines = strtoul (argv[2], &end, 10);
if (*end || max_lines == 0)
{
mu_error ("invalid number of lines");
return 1;
}
MU_ASSERT (mu_locus_track_create (&trk, argv[1], max_lines));
while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0)
{
struct mu_locus_range lr;
char *tok;
n = mu_rtrim_class (buf, MU_CTYPE_SPACE);
if (buf[0] == '\\')
{
long x = strtol (buf+1, &end, 10);
if (*end || x == 0)
{
mu_error ("bad number");
continue;
}
mu_locus_tracker_retreat (trk, x);
}
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);
}
}
return 0;
}