diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2017-06-07 10:24:23 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2017-06-07 10:30:41 +0300 |
commit | 7bca245a054a58c7aaf889243fcacd73a5bd0982 (patch) | |
tree | 28919566d32514904374da47781b01c14c5b4b9c | |
parent | 66da33c354a4a54d0107ea719c77c70ec20d85a3 (diff) | |
download | mailutils-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.ac | 1 | ||||
-rw-r--r-- | include/mailutils/assoc.h | 2 | ||||
-rw-r--r-- | include/mailutils/locus.h | 54 | ||||
-rw-r--r-- | include/mailutils/yyloc.h | 42 | ||||
-rw-r--r-- | libmailutils/Makefile.am | 3 | ||||
-rw-r--r-- | libmailutils/base/assoc.c | 15 | ||||
-rw-r--r-- | libmailutils/base/copyfile.c | 4 | ||||
-rw-r--r-- | libmailutils/locus/Makefile.am | 26 | ||||
-rw-r--r-- | libmailutils/locus/debug.c | 59 | ||||
-rw-r--r-- | libmailutils/locus/ident.c | 96 | ||||
-rw-r--r-- | libmailutils/locus/tracker.c | 168 | ||||
-rw-r--r-- | libmailutils/tests/.gitignore | 1 | ||||
-rw-r--r-- | libmailutils/tests/Makefile.am | 1 | ||||
-rw-r--r-- | libmailutils/tests/tracker.c | 57 |
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; +} + + |