summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2017-06-07 10:24:23 +0300
committerSergey Poznyakoff <gray@gnu.org>2017-06-07 10:30:41 +0300
commit7bca245a054a58c7aaf889243fcacd73a5bd0982 (patch)
tree28919566d32514904374da47781b01c14c5b4b9c
parent66da33c354a4a54d0107ea719c77c70ec20d85a3 (diff)
downloadmailutils-7bca245a054a58c7aaf889243fcacd73a5bd0982.tar.gz
mailutils-7bca245a054a58c7aaf889243fcacd73a5bd0982.tar.bz2
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.
-rw-r--r--configure.ac1
-rw-r--r--include/mailutils/assoc.h2
-rw-r--r--include/mailutils/locus.h54
-rw-r--r--include/mailutils/yyloc.h42
-rw-r--r--libmailutils/Makefile.am3
-rw-r--r--libmailutils/base/assoc.c15
-rw-r--r--libmailutils/base/copyfile.c4
-rw-r--r--libmailutils/locus/Makefile.am26
-rw-r--r--libmailutils/locus/debug.c59
-rw-r--r--libmailutils/locus/ident.c96
-rw-r--r--libmailutils/locus/tracker.c168
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am1
-rw-r--r--libmailutils/tests/tracker.c57
14 files changed, 524 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac
index 3f8418873..c8c8fb620 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/include/mailutils/assoc.h b/include/mailutils/assoc.h
index a8f9845e1..930ff2de5 100644
--- a/include/mailutils/assoc.h
+++ b/include/mailutils/assoc.h
@@ -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);
diff --git a/include/mailutils/locus.h b/include/mailutils/locus.h
new file mode 100644
index 000000000..383b6ecea
--- /dev/null
+++ b/include/mailutils/locus.h
@@ -0,0 +1,54 @@
+#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
diff --git a/include/mailutils/yyloc.h b/include/mailutils/yyloc.h
new file mode 100644
index 000000000..9a82e8b65
--- /dev/null
+++ b/include/mailutils/yyloc.h
@@ -0,0 +1,42 @@
+#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)
+
+
+
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index a105f382e..22aaef6c9 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -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\
diff --git a/libmailutils/base/assoc.c b/libmailutils/base/assoc.c
index b0e353d32..a597ca47c 100644
--- a/libmailutils/base/assoc.c
+++ b/libmailutils/base/assoc.c
@@ -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;
diff --git a/libmailutils/base/copyfile.c b/libmailutils/base/copyfile.c
index 9a72228ce..16518ab75 100644
--- a/libmailutils/base/copyfile.c
+++ b/libmailutils/base/copyfile.c
@@ -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"),
diff --git a/libmailutils/locus/Makefile.am b/libmailutils/locus/Makefile.am
new file mode 100644
index 000000000..827fa8b35
--- /dev/null
+++ b/libmailutils/locus/Makefile.am
@@ -0,0 +1,26 @@
+# 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
+
diff --git a/libmailutils/locus/debug.c b/libmailutils/locus/debug.c
new file mode 100644
index 000000000..1e5e720aa
--- /dev/null
+++ b/libmailutils/locus/debug.c
@@ -0,0 +1,59 @@
+#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);
+}
diff --git a/libmailutils/locus/ident.c b/libmailutils/locus/ident.c
new file mode 100644
index 000000000..7d16f5f64
--- /dev/null
+++ b/libmailutils/locus/ident.c
@@ -0,0 +1,96 @@
+#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;
+}
+
+
+
diff --git a/libmailutils/locus/tracker.c b/libmailutils/locus/tracker.c
new file mode 100644
index 000000000..c8bc99237
--- /dev/null
+++ b/libmailutils/locus/tracker.c
@@ -0,0 +1,168 @@
+#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;
+ }
+}
+
+
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index 39018d55f..3454b7360 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -33,6 +33,7 @@ strout
strtoc
tcli
tempfile
+tracker
url-comp
url-parse
vexp
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index a64824f31..83951ba40 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -67,6 +67,7 @@ noinst_PROGRAMS = \
strout\
strtoc\
tempfile\
+ tracker\
tcli\
url-comp\
url-parse\
diff --git a/libmailutils/tests/tracker.c b/libmailutils/tests/tracker.c
new file mode 100644
index 000000000..68a9b6396
--- /dev/null
+++ b/libmailutils/tests/tracker.c
@@ -0,0 +1,57 @@
+#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;
+}
+
+

Return to:

Send suggestions and report system problems to the System administrator.