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([ ...@@ -1495,6 +1495,7 @@ AC_CONFIG_FILES([
1495 libmailutils/filter/Makefile 1495 libmailutils/filter/Makefile
1496 libmailutils/imapio/Makefile 1496 libmailutils/imapio/Makefile
1497 libmailutils/list/Makefile 1497 libmailutils/list/Makefile
1498 libmailutils/locus/Makefile
1498 libmailutils/mailbox/Makefile 1499 libmailutils/mailbox/Makefile
1499 libmailutils/mailer/Makefile 1500 libmailutils/mailer/Makefile
1500 libmailutils/mime/Makefile 1501 libmailutils/mime/Makefile
......
...@@ -37,6 +37,8 @@ int mu_assoc_install (mu_assoc_t assoc, const char *name, void *value); ...@@ -37,6 +37,8 @@ int mu_assoc_install (mu_assoc_t assoc, const char *name, void *value);
37 37
38 int mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr); 38 int mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr);
39 int mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval); 39 int mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval);
40 int mu_assoc_install_ref2 (mu_assoc_t assoc, const char *name,
41 void *ret_val, const char **ret_name);
40 42
41 int mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator); 43 int mu_assoc_get_iterator (mu_assoc_t assoc, mu_iterator_t *piterator);
42 int mu_assoc_remove (mu_assoc_t assoc, const char *name); 44 int mu_assoc_remove (mu_assoc_t assoc, const char *name);
......
1 #ifndef _MAILUTILS_LOCUS_H
2 #define _MAILUTILS_LOCUS_H
3
4 #include <string.h>
5
6 struct mu_locus_point
7 {
8 char const *mu_file;
9 unsigned mu_line;
10 unsigned mu_col;
11 };
12
13 struct mu_locus_range
14 {
15 struct mu_locus_point beg;
16 struct mu_locus_point end;
17 };
18
19 typedef struct mu_locus_track *mu_locus_track_t;
20
21 int mu_ident_ref (char const *name, char const **refname);
22 int mu_ident_deref (char const *);
23
24 static inline int
25 mu_locus_point_same_file (struct mu_locus_point const *a,
26 struct mu_locus_point const *b)
27 {
28 return a->mu_file == b->mu_file
29 || (a->mu_file && b->mu_file && strcmp(a->mu_file, b->mu_file) == 0);
30 }
31
32 static inline int
33 mu_locus_point_same_line (struct mu_locus_point const *a,
34 struct mu_locus_point const *b)
35 {
36 return mu_locus_point_same_file (a, b) && a->mu_line == b->mu_line;
37 }
38
39 void mu_lrange_debug (struct mu_locus_range const *loc,
40 char const *fmt, ...);
41
42 int mu_locus_track_create (mu_locus_track_t *ret,
43 char const *file_name, size_t max_lines);
44 void mu_locus_track_free (mu_locus_track_t trk);
45 void mu_locus_track_destroy (mu_locus_track_t *trk);
46 size_t mu_locus_track_level (mu_locus_track_t trk);
47 void mu_locus_tracker_advance (struct mu_locus_track *trk,
48 struct mu_locus_range *loc,
49 char const *text, size_t leng);
50 void mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n);
51
52
53
54 #endif
1 #define YYLTYPE struct mu_locus_range
2 #define YYLLOC_DEFAULT(Current, Rhs, N) \
3 do \
4 { \
5 if (N) \
6 { \
7 (Current).beg = YYRHSLOC(Rhs, 1).beg; \
8 (Current).end = YYRHSLOC(Rhs, N).end; \
9 } \
10 else \
11 { \
12 (Current).beg = YYRHSLOC(Rhs, 0).end; \
13 (Current).end = (Current).beg; \
14 } \
15 } while (0)
16 #define YY_LOCATION_PRINT(File, Loc) \
17 do \
18 { \
19 if (!mu_locus_point_same_file (&(Loc).beg, &(Loc).end)) \
20 fprintf (File, "%s:%u.%u-%s:%u.%u", \
21 (Loc).beg.mu_file, \
22 (Loc).beg.mu_line, (Loc).beg.mu_col, \
23 (Loc).end.mu_file, \
24 (Loc).end.mu_line, (Loc).end.mu_col); \
25 else if ((Loc).beg.mu_line != (Loc).end.mu_line) \
26 fprintf (File, "%s:%u.%u-%u.%u", \
27 (Loc).beg.mu_file, \
28 (Loc).beg.mu_line, (Loc).beg.mu_col, \
29 (Loc).end.mu_line, (Loc).end.mu_col); \
30 else if ((Loc).beg.mu_col != (Loc).end.mu_col) \
31 fprintf (File, "%s:%u.%u-%u", \
32 (Loc).beg.mu_file, \
33 (Loc).beg.mu_line, (Loc).beg.mu_col, \
34 (Loc).end.mu_col); \
35 else \
36 fprintf (File, "%s:%u.%u", \
37 (Loc).beg.mu_file, \
38 (Loc).beg.mu_line, (Loc).beg.mu_col); \
39 } while (0)
40
41
42
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
18 18
19 SUBDIRS = \ 19 SUBDIRS = \
20 auth base address list sockaddr cidr cfg cli diag\ 20 auth base address list sockaddr cidr cfg cli diag\
21 filter mailbox mailer mime msgset opt server string stream stdstream\ 21 filter locus mailbox mailer mime msgset opt server string stream stdstream\
22 property url imapio datetime . tests 22 property url imapio datetime . tests
23 23
24 lib_LTLIBRARIES = libmailutils.la 24 lib_LTLIBRARIES = libmailutils.la
...@@ -39,6 +39,7 @@ libmailutils_la_LIBADD = \ ...@@ -39,6 +39,7 @@ libmailutils_la_LIBADD = \
39 filter/libfilter.la\ 39 filter/libfilter.la\
40 imapio/libimapio.la\ 40 imapio/libimapio.la\
41 list/liblist.la\ 41 list/liblist.la\
42 locus/liblocus.la\
42 mailbox/libmailbox.la\ 43 mailbox/libmailbox.la\
43 mailer/libmailer.la\ 44 mailer/libmailer.la\
44 mime/libmime.la\ 45 mime/libmime.la\
......
...@@ -387,7 +387,9 @@ mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr) ...@@ -387,7 +387,9 @@ mu_assoc_lookup_ref (mu_assoc_t assoc, const char *name, void *dataptr)
387 } 387 }
388 388
389 int 389 int
390 mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval) 390 mu_assoc_install_ref2 (mu_assoc_t assoc, const char *name,
391 void *ret_val,
392 const char **ret_name)
391 { 393 {
392 int rc; 394 int rc;
393 int inst; 395 int inst;
...@@ -425,11 +427,20 @@ mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval) ...@@ -425,11 +427,20 @@ mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval)
425 assoc_elem_link (assoc, idx); 427 assoc_elem_link (assoc, idx);
426 } 428 }
427 429
428 *(void**)pval = &assoc->tab[idx]->data; 430 *(void**)ret_val = &assoc->tab[idx]->data;
431 if (ret_name)
432 *ret_name = assoc->tab[idx]->name;
433
429 return inst ? 0 : MU_ERR_EXISTS; 434 return inst ? 0 : MU_ERR_EXISTS;
430 } 435 }
431 436
432 int 437 int
438 mu_assoc_install_ref (mu_assoc_t assoc, const char *name, void *pval)
439 {
440 return mu_assoc_install_ref2 (assoc, name, pval, NULL);
441 }
442
443 int
433 mu_assoc_remove (mu_assoc_t assoc, const char *name) 444 mu_assoc_remove (mu_assoc_t assoc, const char *name)
434 { 445 {
435 int rc; 446 int rc;
......
...@@ -163,7 +163,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, ...@@ -163,7 +163,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags,
163 rc = mu_stream_ioctl (dst, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, trans); 163 rc = mu_stream_ioctl (dst, MU_IOCTL_TRANSPORT, MU_IOCTL_OP_GET, trans);
164 if (rc == 0) 164 if (rc == 0)
165 { 165 {
166 if (fchmod ((int) trans[0], mode)) 166 if (fchmod ((int) (intptr_t) trans[0], mode))
167 { 167 {
168 mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, 168 mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR,
169 (_("%s: cannot chmod: %s"), 169 (_("%s: cannot chmod: %s"),
...@@ -193,7 +193,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags, ...@@ -193,7 +193,7 @@ copy_regular_file (const char *srcpath, const char *dstpath, int flags,
193 193
194 if (gid != -1) 194 if (gid != -1)
195 { 195 {
196 if (fchown ((int) trans[0], uid, gid)) 196 if (fchown ((int) (intptr_t) trans[0], uid, gid))
197 { 197 {
198 mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR, 198 mu_debug (MU_DEBCAT_STREAM, MU_DEBUG_ERROR,
199 (_("%s: cannot chown to %lu.%lu: %s"), 199 (_("%s: cannot chown to %lu.%lu: %s"),
......
1 # GNU Mailutils -- a suite of utilities for electronic mail
2 # Copyright (C) 2017 Free Software Foundation, Inc.
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 3 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General
15 # Public License along with this library. If not, see
16 # <http://www.gnu.org/licenses/>.
17
18 noinst_LTLIBRARIES = liblocus.la
19
20 liblocus_la_SOURCES = \
21 ident.c\
22 debug.c\
23 tracker.c
24
25 AM_CPPFLAGS = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
26
1 #include <stdlib.h>
2 #include <stdarg.h>
3 #include <mailutils/types.h>
4 #include <mailutils/locus.h>
5 #include <mailutils/error.h>
6 #include <mailutils/errno.h>
7 #include <mailutils/diag.h>
8 #include <mailutils/stream.h>
9 #include <mailutils/stdstream.h>
10
11 void
12 mu_lrange_debug (struct mu_locus_range const *loc,
13 char const *fmt, ...)
14 {
15 va_list ap;
16 int rc, mode;
17
18 rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
19 MU_IOCTL_LOGSTREAM_GET_MODE, &mode);
20 if (rc == 0)
21 {
22 int new_mode = mode & ~MU_LOGMODE_LOCUS;
23 rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
24 MU_IOCTL_LOGSTREAM_SET_MODE, &new_mode);
25 }
26
27 if (loc->beg.mu_col == 0)
28 mu_debug_log_begin ("%s:%u", loc->beg.mu_file, loc->beg.mu_line);
29 else if (!mu_locus_point_same_file (&loc->beg, &loc->end))
30 mu_debug_log_begin ("%s:%u.%u-%s:%u.%u",
31 loc->beg.mu_file,
32 loc->beg.mu_line, loc->beg.mu_col,
33 loc->end.mu_file,
34 loc->end.mu_line, loc->end.mu_col);
35 else if (loc->beg.mu_line != loc->end.mu_line)
36 mu_debug_log_begin ("%s:%u.%u-%u.%u",
37 loc->beg.mu_file,
38 loc->beg.mu_line, loc->beg.mu_col,
39 loc->end.mu_line, loc->end.mu_col);
40 else if (loc->beg.mu_col != loc->end.mu_col)
41 mu_debug_log_begin ("%s:%u.%u-%u",
42 loc->beg.mu_file,
43 loc->beg.mu_line, loc->beg.mu_col,
44 loc->end.mu_col);
45 else
46 mu_debug_log_begin ("%s:%u.%u",
47 loc->beg.mu_file,
48 loc->beg.mu_line, loc->beg.mu_col);
49
50 mu_stream_write (mu_strerr, ": ", 2, NULL);
51
52 va_start (ap, fmt);
53 mu_stream_vprintf (mu_strerr, fmt, ap);
54 va_end (ap);
55 mu_debug_log_nl ();
56 if (rc == 0)
57 mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
58 MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
59 }
1 #include <stdlib.h>
2 #include <mailutils/types.h>
3 #include <mailutils/assoc.h>
4 #include <mailutils/locus.h>
5 #include <mailutils/error.h>
6 #include <mailutils/errno.h>
7 #include <mailutils/diag.h>
8 #include <mailutils/list.h>
9
10 struct mu_ident_ref
11 {
12 size_t count;
13 };
14
15 static mu_assoc_t nametab;
16
17 int
18 mu_ident_ref (char const *name, char const **refname)
19 {
20 int rc;
21 struct mu_ident_ref *ref, **refptr;
22
23 if (!name)
24 return EINVAL;
25 if (!refname)
26 return MU_ERR_OUT_PTR_NULL;
27
28 if (!nametab)
29 {
30 rc = mu_assoc_create (&nametab, 0);
31 if (rc)
32 {
33 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_create", NULL, rc);
34 return rc;
35 }
36 mu_assoc_set_destroy_item (nametab, mu_list_free_item);
37 }
38 rc = mu_assoc_install_ref2 (nametab, name, &refptr, refname);
39 switch (rc)
40 {
41 case 0:
42 ref = malloc (sizeof *ref);
43 if (!ref)
44 {
45 rc = errno;
46 mu_assoc_remove (nametab, name);
47 return rc;
48 }
49 ref->count = 0;
50 break;
51
52 case MU_ERR_EXISTS:
53 ref = *refptr;
54 break;
55
56 default:
57 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_install_ref2", name, rc);
58 return rc;
59 }
60
61 ref->count++;
62 return 0;
63 }
64
65 int
66 mu_ident_deref (char const *name)
67 {
68 struct mu_ident_ref *ref;
69 int rc;
70
71 if (!name)
72 return EINVAL;
73 if (!nametab)
74 return 0;
75
76 rc = mu_assoc_lookup (nametab, name, &ref);
77 switch (rc)
78 {
79 case 0:
80 if (--ref->count == 0)
81 mu_assoc_remove (nametab, name);
82 break;
83
84 case MU_ERR_NOENT:
85 break;
86
87 default:
88 mu_diag_funcall (MU_DIAG_ERROR, "mu_assoc_lookup", name, rc);
89 return rc;
90 }
91
92 return 0;
93 }
94
95
96
1 #include <stdlib.h>
2 #include <errno.h>
3 #include <mailutils/types.h>
4 #include <mailutils/locus.h>
5
6 struct mu_locus_track
7 {
8 char const *file_name; /* Name of the source file */
9 size_t max_lines; /* Max. number of lines history kept by tracker */
10 size_t head; /* Bottom of stack */
11 size_t level; /* Number of elements on stack */
12 unsigned hline; /* Number of line corresponding to cols[head] */
13 unsigned *cols; /* Cyclic stack */
14 };
15
16 int
17 mu_locus_track_create (mu_locus_track_t *ret,
18 char const *file_name, size_t max_lines)
19 {
20 int rc;
21 struct mu_locus_track *trk;
22
23 trk = malloc (sizeof *trk);
24 if (!trk)
25 return errno;
26 trk->cols = calloc (max_lines, sizeof (trk->cols[0]));
27 if (!trk->cols)
28 {
29 rc = errno;
30 free (trk);
31 return rc;
32 }
33 rc = mu_ident_ref (file_name, &trk->file_name);
34 if (rc)
35 {
36 free (trk->cols);
37 free (trk);
38 return rc;
39 }
40
41 trk->max_lines = max_lines;
42 trk->head = 0;
43 trk->level = 0;
44 trk->hline = 1;
45 trk->cols[0] = 0;
46
47 *ret = trk;
48 return 0;
49 }
50
51 void
52 mu_locus_track_free (mu_locus_track_t trk)
53 {
54 if (trk)
55 {
56 mu_ident_deref (trk->file_name);
57 free (trk->cols);
58 free (trk);
59 }
60 }
61
62 void
63 mu_locus_track_destroy (mu_locus_track_t *trk)
64 {
65 if (trk)
66 {
67 mu_locus_track_free (*trk);
68 *trk = NULL;
69 }
70 }
71
72 size_t
73 mu_locus_track_level (mu_locus_track_t trk)
74 {
75 return trk->level;
76 }
77
78 static inline unsigned *
79 cols_tos_ptr (mu_locus_track_t trk)
80 {
81 return &trk->cols[(trk->head + trk->level) % trk->max_lines];
82 }
83
84 static inline unsigned
85 cols_peek (mu_locus_track_t trk, size_t n)
86 {
87 return trk->cols[(trk->head + n) % trk->max_lines];
88 }
89
90 static inline unsigned *
91 push (mu_locus_track_t trk)
92 {
93 unsigned *ptr;
94 if (trk->level == trk->max_lines)
95 {
96 trk->head++;
97 trk->hline++;
98 }
99 else
100 trk->level++;
101 *(ptr = cols_tos_ptr (trk)) = 0;
102 return ptr;
103 }
104
105 static inline unsigned *
106 pop (mu_locus_track_t trk)
107 {
108 if (trk->level == 0)
109 {
110 *cols_tos_ptr (trk) = 0;
111 return NULL; //FIXME
112 }
113 trk->level--;
114 return cols_tos_ptr (trk);
115 }
116
117 void
118 mu_locus_tracker_advance (struct mu_locus_track *trk,
119 struct mu_locus_range *loc,
120 char const *text, size_t leng)
121 {
122 unsigned *ptr;
123
124 if (text == NULL || leng == 0)
125 return;
126
127 loc->beg.mu_file = loc->end.mu_file = trk->file_name;
128 loc->beg.mu_line = trk->hline + trk->level;
129 ptr = cols_tos_ptr (trk);
130 loc->beg.mu_col = *ptr + 1;
131 while (leng--)
132 {
133 (*ptr)++;
134 if (*text == '\n')
135 ptr = push (trk);
136 text++;
137 }
138 if (*ptr)
139 {
140 loc->end.mu_line = trk->hline + trk->level;
141 loc->end.mu_col = *ptr;
142 }
143 else
144 {
145 loc->end.mu_line = trk->hline + trk->level - 1;
146 loc->end.mu_col = cols_peek (trk, trk->level - 1) - 1;
147 }
148 }
149
150 void
151 mu_locus_tracker_retreat (struct mu_locus_track *trk, size_t n)
152 {
153 unsigned *ptr;
154
155 ptr = cols_tos_ptr (trk);
156 while (n--)
157 {
158 if (*ptr == 0)
159 {
160 ptr = pop (trk);
161 if (!ptr)
162 break;
163 }
164 --*ptr;
165 }
166 }
167
168
...@@ -33,6 +33,7 @@ strout ...@@ -33,6 +33,7 @@ strout
33 strtoc 33 strtoc
34 tcli 34 tcli
35 tempfile 35 tempfile
36 tracker
36 url-comp 37 url-comp
37 url-parse 38 url-parse
38 vexp 39 vexp
......
...@@ -67,6 +67,7 @@ noinst_PROGRAMS = \ ...@@ -67,6 +67,7 @@ noinst_PROGRAMS = \
67 strout\ 67 strout\
68 strtoc\ 68 strtoc\
69 tempfile\ 69 tempfile\
70 tracker\
70 tcli\ 71 tcli\
71 url-comp\ 72 url-comp\
72 url-parse\ 73 url-parse\
......
1 #include <mailutils/mailutils.h>
2 #include <mailutils/locus.h>
3
4 int
5 main (int argc, char **argv)
6 {
7 unsigned long max_lines;
8 char *end;
9 mu_locus_track_t trk;
10 int rc;
11 char *buf = NULL;
12 size_t size, n;
13
14 mu_set_program_name (argv[0]);
15 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
16
17 if (argc != 3)
18 {
19 mu_error ("usage: %s FILE LINES", mu_program_name);
20 return 1;
21 }
22 max_lines = strtoul (argv[2], &end, 10);
23 if (*end || max_lines == 0)
24 {
25 mu_error ("invalid number of lines");
26 return 1;
27 }
28
29 MU_ASSERT (mu_locus_track_create (&trk, argv[1], max_lines));
30 while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0)
31 {
32 struct mu_locus_range lr;
33 char *tok;
34
35 n = mu_rtrim_class (buf, MU_CTYPE_SPACE);
36 if (buf[0] == '\\')
37 {
38 long x = strtol (buf+1, &end, 10);
39 if (*end || x == 0)
40 {
41 mu_error ("bad number");
42 continue;
43 }
44 mu_locus_tracker_retreat (trk, x);
45 }
46 else
47 {
48 mu_c_str_unescape (buf, "\\\n", "\\n", &tok);
49 mu_locus_tracker_advance (trk, &lr, tok, strlen (tok));
50 free (tok);
51 mu_lrange_debug (&lr, "%s", buf);
52 }
53 }
54 return 0;
55 }
56
57