commit-mailutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU Mailutils branch, master, updated. release-2.2-273-g75755ec


From: Sergey Poznyakoff
Subject: [SCM] GNU Mailutils branch, master, updated. release-2.2-273-g75755ec
Date: Wed, 08 Dec 2010 15:20:33 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Mailutils".

http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=75755ec7febf8c891b4b809120f3da77e1e15549

The branch, master has been updated
       via  75755ec7febf8c891b4b809120f3da77e1e15549 (commit)
      from  9e253b395de6ea7839b7f2b04b1a28892af514e7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 75755ec7febf8c891b4b809120f3da77e1e15549
Author: Sergey Poznyakoff <address@hidden>
Date:   Wed Dec 8 17:15:52 2010 +0200

    Implement line number output in linecon and inline-comment filters.
    
    * libmailutils/filter/inline-comment.c: Implement line number info
    facility.
    * libmailutils/filter/linecon.c: Likewise.
    * libmailutils/stream/logstream.c (_log_done, _log_close): Always
    close/destroy the underlying transport stream.
    * comsat/action.c: Rewrite using a table-driven parser.
    Use line-info facility of the linecon filter.

-----------------------------------------------------------------------

Summary of changes:
 comsat/action.c                      |  492 +++++++++++++++++++---------------
 libmailutils/filter/inline-comment.c |  142 ++++++++--
 libmailutils/filter/linecon.c        |  154 +++++++++--
 libmailutils/stream/logstream.c      |    7 +-
 4 files changed, 527 insertions(+), 268 deletions(-)

diff --git a/comsat/action.c b/comsat/action.c
index f064723..28ac348 100644
--- a/comsat/action.c
+++ b/comsat/action.c
@@ -184,142 +184,6 @@ const char *default_action =
 #include "biff.rc.h"
 ;
 
-static void
-action_beep (mu_stream_t tty)
-{
-  mu_stream_write (tty, "\a\a", 2, NULL);
-  mu_stream_flush (tty);
-}
-
-static void
-echo_string (mu_stream_t tty, char *str)
-{
-  if (!str)
-    return;
-  mu_stream_write (tty, str, strlen (str), NULL);
-}
-
-static void
-action_echo (mu_stream_t tty, int omit_newline, int argc, char **argv)
-{
-  int i;
-
-  for (i = 0;;)
-    {
-      echo_string (tty, argv[i]);
-      if (++i < argc)
-       echo_string (tty, " ");
-      else
-       break;
-    }
-  if (!omit_newline)
-    echo_string (tty, "\n");
-}
-
-static void
-action_exec (mu_stream_t tty, int argc, char **argv)
-{
-  mu_stream_t pstream;
-  struct stat stb;
-  int status;
-  
-  if (argc == 0)
-    {
-      mu_diag_output (MU_DIAG_ERROR, _("no arguments for exec"));
-      return;
-    }
-
-  if (argv[0][0] != '/')
-    {
-      mu_diag_output (MU_DIAG_ERROR, _("not an absolute pathname: %s"),
-                     argv[0]);
-      return;
-    }
-
-  if (stat (argv[0], &stb))
-    {
-      mu_diag_funcall (MU_DIAG_ERROR, "stat", argv[0], errno);
-      return;
-    }
-
-  if (stb.st_mode & (S_ISUID|S_ISGID))
-    {
-      mu_diag_output (MU_DIAG_ERROR,
-                     _("will not execute set[ug]id programs"));
-      return;
-    }
-
-  status = mu_prog_stream_create (&pstream,
-                                 argv[0], argc, argv,
-                                 MU_PROG_HINT_ERRTOOUT,
-                                 NULL,
-                                 MU_STREAM_READ);
-  if (status)
-    {
-      mu_diag_funcall (MU_DIAG_ERROR, "mu_prog_stream_create", argv[0],
-                      status);
-      return;
-    }
-  mu_stream_copy (tty, pstream, 0, NULL);
-  mu_stream_destroy (&pstream);
-}
-
-static mu_stream_t
-open_rc (const char *filename, mu_stream_t tty)
-{
-  struct stat stb;
-  struct passwd *pw = getpwnam (username);
-  mu_stream_t stream, input;
-  int rc;
-  
-  /* To be on the safe side, we do not allow root to have his .biffrc */
-  if (!allow_biffrc || pw->pw_uid == 0)
-    return NULL;
-  if (stat (filename, &stb) == 0)
-    {
-      if (stb.st_uid != pw->pw_uid)
-       {
-         mu_diag_output (MU_DIAG_NOTICE, _("%s's %s is not owned by %s"),
-                 username, filename, username);
-         return NULL;
-       }
-      if ((stb.st_mode & 0777) != 0600)
-       {
-         mu_stream_printf (tty, "%s\n",
-                           _("Warning: your .biffrc has wrong permissions"));
-         mu_diag_output (MU_DIAG_NOTICE, _("%s's %s has wrong permissions"),
-                 username, filename);
-         return NULL;
-       }
-    }
-  rc = mu_file_stream_create (&input, filename, MU_STREAM_READ);
-  if (rc)
-    {
-      if (rc != ENOENT)
-       {
-         mu_stream_printf (tty, _("Cannot open .biffrc file: %s\n"),
-                           mu_strerror (rc));
-         mu_diag_output (MU_DIAG_NOTICE, _("cannot open %s for %s: %s"),
-                         filename, username, mu_strerror (rc));
-       }
-      return NULL;
-    }
-  rc = mu_filter_create (&stream, input, "LINECON", MU_FILTER_DECODE,
-                        MU_STREAM_READ);
-  mu_stream_unref (input);
-  if (rc)
-    {
-      mu_stream_printf (tty,
-                       _("Cannot create filter for your .biffrc file: %s\n"),
-                       mu_strerror (rc));
-      mu_diag_output (MU_DIAG_NOTICE,
-                     _("cannot create filter for file %s of %s: %s"),
-                     filename, username, mu_strerror (rc));
-      return NULL;
-    }
-  return stream;
-}
-
 static int
 need_crlf (mu_stream_t str)
 {
@@ -434,15 +298,219 @@ open_default_tty (const char *device)
                   default_filters);
 }
 
+
 struct biffrc_environ
 {
   mu_stream_t tty;
+  mu_stream_t logstr;
   mu_message_t msg;
   mu_stream_t input;
   struct mu_locus locus;
   int use_default;
+  char *errbuf;
+  size_t errsize;
+};
+
+static void
+report_error (struct biffrc_environ *env, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  mu_vasnprintf (&env->errbuf, &env->errsize, fmt, ap);
+  mu_stream_printf (env->logstr, "%s\n", env->errbuf);
+  mu_diag_output (MU_DIAG_ERROR, "%s", env->errbuf);
+  va_end (ap);
+}
+                 
+  
+static void
+action_beep (struct biffrc_environ *env, size_t argc, char **argv)
+{
+  mu_stream_write (env->tty, "\a\a", 2, NULL);
+  mu_stream_flush (env->tty);
+}
+
+static void
+echo_string (mu_stream_t tty, char *str)
+{
+  if (!str)
+    return;
+  mu_stream_write (tty, str, strlen (str), NULL);
+}
+
+static void
+action_echo (struct biffrc_environ *env, size_t argc, char **argv)
+{
+  int i = 1;
+  int omit_newline;
+
+  if (argc > 2 && strcmp (argv[i], "-n") == 0)
+    {
+      omit_newline = 1;
+      i++;
+    }
+  for (;;)
+    {
+      echo_string (env->tty, argv[i]);
+      if (++i < argc)
+       echo_string (env->tty, " ");
+      else
+       break;
+    }
+  if (!omit_newline)
+    echo_string (env->tty, "\n");
+}
+
+static void
+action_exec (struct biffrc_environ *env, size_t argc, char **argv)
+{
+  mu_stream_t pstream;
+  struct stat stb;
+  int status;
+
+  argc--;
+  argv++;
+  
+  if (argv[0][0] != '/')
+    {
+      report_error (env, _("not an absolute pathname: %s"), argv[0]);
+      return;
+    }
+
+  if (stat (argv[0], &stb))
+    {
+      mu_diag_funcall (MU_DIAG_ERROR, "stat", argv[0], errno);
+      return;
+    }
+
+  if (stb.st_mode & (S_ISUID|S_ISGID))
+    {
+      report_error (env, _("will not execute set[ug]id programs"));
+      return;
+    }
+
+  status = mu_prog_stream_create (&pstream,
+                                 argv[0], argc, argv,
+                                 MU_PROG_HINT_ERRTOOUT,
+                                 NULL,
+                                 MU_STREAM_READ);
+  if (status)
+    {
+      report_error (env, "mu_prog_stream_create(%s) failed: %s", argv[0],
+                   mu_strerror (status));
+      return;
+    }
+  mu_stream_copy (env->tty, pstream, 0, NULL);
+  mu_stream_destroy (&pstream);
+}
+
+static void
+action_default (struct biffrc_environ *env, size_t argc, char **argv)
+{
+  env->use_default = 1;
+}
+
+static void
+action_tty (struct biffrc_environ *env, size_t argc, char **argv)
+{
+  mu_stream_t ntty = open_tty (argv[1], argc - 2, argv + 2);
+  if (!ntty)
+    report_error (env, _("cannot open tty %s"), argv[1]);
+
+  mu_stream_destroy (&env->tty);
+  env->tty = ntty;
+}
+
+static mu_stream_t
+open_rc (const char *filename, mu_stream_t tty)
+{
+  struct stat stb;
+  struct passwd *pw = getpwnam (username);
+  mu_stream_t stream, input;
+  int rc;
+  static char *linecon_args[] = { "linecon", "-i", "#line", NULL };
+  
+  /* To be on the safe side, we do not allow root to have his .biffrc */
+  if (!allow_biffrc || pw->pw_uid == 0)
+    return NULL;
+  if (stat (filename, &stb) == 0)
+    {
+      if (stb.st_uid != pw->pw_uid)
+       {
+         mu_diag_output (MU_DIAG_NOTICE, _("%s's %s is not owned by %s"),
+                 username, filename, username);
+         return NULL;
+       }
+      if ((stb.st_mode & 0777) != 0600)
+       {
+         mu_stream_printf (tty, "%s\n",
+                           _("Warning: your .biffrc has wrong permissions"));
+         mu_diag_output (MU_DIAG_NOTICE, _("%s's %s has wrong permissions"),
+                 username, filename);
+         return NULL;
+       }
+    }
+  rc = mu_file_stream_create (&input, filename, MU_STREAM_READ);
+  if (rc)
+    {
+      if (rc != ENOENT)
+       {
+         mu_stream_printf (tty, _("Cannot open .biffrc file: %s\n"),
+                           mu_strerror (rc));
+         mu_diag_output (MU_DIAG_NOTICE, _("cannot open %s for %s: %s"),
+                         filename, username, mu_strerror (rc));
+       }
+      return NULL;
+    }
+  rc = mu_filter_create_args (&stream, input,
+                             "LINECON",
+                             MU_ARRAY_SIZE (linecon_args) - 1,
+                             (const char **)linecon_args,
+                             MU_FILTER_DECODE,
+                             MU_STREAM_READ);
+  mu_stream_unref (input);
+  if (rc)
+    {
+      mu_stream_printf (tty,
+                       _("Cannot create filter for your .biffrc file: %s\n"),
+                       mu_strerror (rc));
+      mu_diag_output (MU_DIAG_NOTICE,
+                     _("cannot create filter for file %s of %s: %s"),
+                     filename, username, mu_strerror (rc));
+      return NULL;
+    }
+  return stream;
+}
+
+struct biffrc_stmt
+{
+  const char *id;
+  int argmin;
+  int argmax;
+  int expand;
+  void (*handler) (struct biffrc_environ *env, size_t argc, char **argv);
+};
+
+struct biffrc_stmt biffrc_tab[] = {
+  { "beep", 1, 1, 0, action_beep },
+  { "tty", 2, -1, 0, action_tty },
+  { "echo", 2, -1, 1, action_echo },
+  { "exec", 2, -1, 1, action_exec },
+  { "default", 1, 1, 0, action_default },
+  { NULL }
 };
 
+struct biffrc_stmt *
+find_stmt (const char *name)
+{
+  struct biffrc_stmt *p;
+
+  for (p = biffrc_tab; p->id; p++)
+    if (strcmp (name, p->id) == 0)
+      return p;
+  return NULL;
+}
+
 void
 eval_biffrc (struct biffrc_environ *env)
 {
@@ -458,100 +526,85 @@ eval_biffrc (struct biffrc_environ *env)
     {
       mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
                       MU_IOCTL_LOGSTREAM_SET_LOCUS, &env->locus);
-      if (mu_wordsplit (stmt, &ws, wsflags) == 0 && ws.ws_wordc)
+      mu_stream_ioctl (env->logstr, MU_IOCTL_LOGSTREAM,
+                      MU_IOCTL_LOGSTREAM_SET_LOCUS, &env->locus);
+      if (strncmp (stmt, "#line ", 6) == 0)
        {
-         if (strcmp (ws.ws_wordv[0], "beep") == 0)
+         char *p;
+         
+         env->locus.mu_line = strtoul (stmt + 6, &p, 10);
+         if (*p != '\n')
            {
-             /* FIXME: excess arguments are ignored */
-             action_beep (env->tty);
+             report_error (env, _("malformed #line directive: %s"));
            }
          else
            {
-             /* Rest of actions require keyword expansion */
-             int i;
-             int n_option = ws.ws_wordc > 1 &&
-               strcmp (ws.ws_wordv[1], "-n") == 0;
-             
-             for (i = 1; i < ws.ws_wordc; i++)
-               {
-                 char *oldarg = ws.ws_wordv[i];
-                 ws.ws_wordv[i] = expand_line (ws.ws_wordv[i], env->msg);
-                 free (oldarg);
-                 if (!ws.ws_wordv[i])
-                   break;
-               }
-             
-             if (strcmp (ws.ws_wordv[0], "tty") == 0)
-               {
-                 mu_stream_t ntty = open_tty (ws.ws_wordv[1],
-                                              ws.ws_wordc - 2,
-                                              ws.ws_wordv + 2);
-                 if (!ntty)
-                   {
-                     mu_stream_printf (env->tty,
-                                       _("%s:%d: cannot open tty\n"),
-                                       env->locus.mu_file,
-                                       env->locus.mu_line);
-                     break;
-                   }
-                 mu_stream_destroy (&env->tty);
-                 env->tty = ntty;
-               }
-             else if (strcmp (ws.ws_wordv[0], "echo") == 0)
+             mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
+                              MU_IOCTL_LOGSTREAM_SET_LOCUS, &env->locus);
+             mu_stream_ioctl (env->logstr, MU_IOCTL_LOGSTREAM,
+                              MU_IOCTL_LOGSTREAM_SET_LOCUS, &env->locus);
+           }
+         continue;
+       }
+      
+      if (mu_wordsplit (stmt, &ws, wsflags) == 0)
+       {
+         struct biffrc_stmt *sp;
+         
+         if (ws.ws_wordc == 0)
+           {
+             env->locus.mu_line++;
+             continue;
+           }
+
+         sp = find_stmt (ws.ws_wordv[0]);
+         if (!sp)
+           report_error (env, _("unknown keyword"));
+         else if (ws.ws_wordc < sp->argmin)
+           {
+             report_error (env, _("too few arguments"));
+           }
+         else if (sp->argmax != -1 && ws.ws_wordc > sp->argmax)
+           {
+             report_error (env, _("too many arguments"));
+           }
+         else
+           {
+             if (sp->expand)
                {
-                 int argc = ws.ws_wordc - 1;
-                 char **argv = ws.ws_wordv + 1;
-                 if (n_option)
+                 size_t i;
+                 
+                 for (i = 1; i < ws.ws_wordc; i++)
                    {
-                     argc--;
-                     argv++;
+                     char *oldarg = ws.ws_wordv[i];
+                     ws.ws_wordv[i] = expand_line (ws.ws_wordv[i], env->msg);
+                     free (oldarg);
+                     if (!ws.ws_wordv[i])
+                       break;
                    }
-                 action_echo (env->tty, n_option, argc, argv);
                }
-             else if (strcmp (ws.ws_wordv[0], "exec") == 0)
-               {
-                 action_exec (env->tty, ws.ws_wordc - 1, ws.ws_wordv + 1);
-               }
-             else if (strcmp (ws.ws_wordv[0], "default") == 0)
-               {
-                 env->use_default = 1;
-               }
-             else
-               {
-                 mu_stream_printf (env->tty,
-                                   _("%s:%d: unknown keyword\n"),
-                                   env->locus.mu_file,
-                                   env->locus.mu_line);
-                 mu_diag_output (MU_DIAG_ERROR, _("unknown keyword %s"),
-                                 ws.ws_wordv[0]);
-                 break;
-               }
-           } 
+
+             sp->handler (env, ws.ws_wordc, ws.ws_wordv);
+           }
        }
       else
-       {
-         const char *diag = mu_wordsplit_strerror (&ws);
-         mu_stream_printf (env->tty,
-                           _("%s:%d: %s\n"),
-                           env->locus.mu_file,
-                           env->locus.mu_line,
-                           diag);
-         mu_diag_output (MU_DIAG_ERROR, "%s", diag);
-       }
+       report_error (env, "%s", mu_wordsplit_strerror (&ws));
       
       wsflags |= MU_WRDSF_REUSE;
-      /* FIXME: line number is incorrect if .biffrc contains
-        escaped newlines */
       env->locus.mu_line++;
     }
   free (stmt);
   mu_wordsplit_free (&ws);
+  mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
+                  MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL);
+  mu_stream_ioctl (env->logstr, MU_IOCTL_LOGSTREAM,
+                  MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL);
 }
 
-
 void
 run_user_action (const char *device, mu_message_t msg)
 {
+  int rc, mode;
   mu_stream_t stream;
   struct biffrc_environ env;
 
@@ -559,7 +612,25 @@ run_user_action (const char *device, mu_message_t msg)
   if (!env.tty)
     return;
   env.msg = msg;
+
+  env.errbuf = NULL;
+  env.errsize = 0;
   
+  rc = mu_log_stream_create (&env.logstr, env.tty); 
+  if (rc)
+    {
+      mu_diag_output (MU_DIAG_ERROR,
+                     _("cannot create log stream: %s"),
+                     mu_strerror (rc));
+      mu_stream_destroy (&env.tty);
+      return;
+    }
+  mode = MU_LOGMODE_LOCUS;
+  mu_stream_ioctl (env.logstr, MU_IOCTL_LOGSTREAM,
+                  MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
+  mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
+                  MU_IOCTL_LOGSTREAM_SET_MODE, &mode);
+
   env.input = open_rc (biffrc, env.tty);
   if (env.input)
     {
@@ -612,8 +683,7 @@ run_user_action (const char *device, mu_message_t msg)
        }
     }
   
-  mu_stream_ioctl (mu_strerr, MU_IOCTL_LOGSTREAM,
-                  MU_IOCTL_LOGSTREAM_SET_LOCUS, NULL);
-
+  mu_stream_destroy (&env.logstr);
   mu_stream_destroy (&env.tty);
+  free (env.errbuf);
 }
diff --git a/libmailutils/filter/inline-comment.c 
b/libmailutils/filter/inline-comment.c
index 747ba97..8def8b7 100644
--- a/libmailutils/filter/inline-comment.c
+++ b/libmailutils/filter/inline-comment.c
@@ -23,14 +23,18 @@
 
    The following options modify this behavior:
 
-      -r   Remove empty lines, i.e. the ones that contain only whitespace
-           characters.
-      -s   Squeeze whitespace.  Each sequence of two or more whitespace
-           characters encountered on input is replaced by a single space
-          character on output.
-      -S   A "following whitespace mode".  A comment sequence is recognized
-           only if followed by a whitespace character.  The character itself
-          is retained on output.  
+      -i STR  Emit line number information after each contiguous sequence
+              of removed lines.  STR supplies "information starter" -- a
+             sequence of characters which is output before the actual line
+             number.
+      -r      Remove empty lines, i.e. the ones that contain only whitespace
+              characters.
+      -s      Squeeze whitespace.  Each sequence of two or more whitespace
+              characters encountered on input is replaced by a single space
+             character on output.
+      -S      A "following whitespace mode".  A comment sequence is
+              recognized only if followed by a whitespace character.
+             The character itself is retained on output.  
 
    In encode mode, this filter adds a comment sequence at the beginning
    of each line.
@@ -49,16 +53,19 @@
 #include <mailutils/errno.h>
 #include <mailutils/filter.h>
 #include <mailutils/cctype.h>
+#include <mailutils/io.h>
 
 enum ilcmt_state
   {
     ilcmt_initial,
     ilcmt_newline,
+    ilcmt_newline_ac,
     ilcmt_copy,
     ilcmt_comment,
     ilcmt_partial,
     ilcmt_comment_ws,
     ilcmt_ws,
+    ilcmt_rollback,
     ilcmt_rollback_ws,
     ilcmt_rollback_com
   };
@@ -71,13 +78,20 @@ enum ilcmt_state
                                         whitespace character.
                                         In encode mode: output a space after
                                         each comment prefix. */
+#define ILCMT_LINE_INFO          0x08 /* Emit line number information */ 
+
+#define ILCMT_COMMENT_STATIC     0x0100
+#define ILCMT_LINE_INFO_STATIC   0x0200
 
 struct ilcmt_data
 {
   enum ilcmt_state state;  /* Current state */
-  char *comment;           /* Comment sequence ... */ 
+  char *comment;           /* Comment sequence ... */
   size_t length;           /* and its length */
   int flags;               /* ILCMT_ flags */
+  char *line_info_starter;   /* Starter for line number info lines */
+  unsigned long line_number; /* Current line number */
+  char sbuf[3];            /* Static location for single-character strings */
   char *buf;               /* Rollback buffer ... */
   size_t size;             /* and its size */
   size_t level;            /* In ilcmt_partial and ilcmt_rollback_com
@@ -116,6 +130,17 @@ ilcmt_save (struct ilcmt_data *pd, int c)
   return 0;
 }
 
+static void
+_ilcmt_free (struct ilcmt_data *pd)
+{
+  if (!(pd->flags & ILCMT_COMMENT_STATIC))
+    free (pd->comment);
+  if ((pd->flags & ILCMT_LINE_INFO) &&
+      !(pd->flags & ILCMT_LINE_INFO_STATIC))
+    free (pd->line_info_starter);
+  free (pd->buf);
+}
+
 static enum mu_filter_result
 _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
                struct mu_filter_io *iobuf)
@@ -131,8 +156,7 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
       return mu_filter_ok;
       
     case mu_filter_done:
-      free (pd->comment);
-      free (pd->buf);
+      _ilcmt_free (pd);
       return mu_filter_ok;
       
     default:
@@ -150,14 +174,25 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
        {
        case ilcmt_initial:
        case ilcmt_newline:
+       case ilcmt_newline_ac:
          if (*iptr == *pd->comment)
            {
              iptr++;
              pd->level = 1;
              pd->state = ilcmt_partial;
            }
+         else if (pd->state == ilcmt_newline_ac)
+           {
+             mu_asnprintf (&pd->buf, &pd->size, "%s %lu\n",
+                           pd->line_info_starter,
+                           pd->line_number);
+             pd->level = strlen (pd->buf);
+             pd->replay = 0;
+             pd->state = ilcmt_rollback;
+           }
          else if (*iptr == '\n')
            {
+             pd->line_number++;
              if (pd->flags & ILCMT_REMOVE_EMPTY_LINES)
                {
                  iptr++;
@@ -230,6 +265,7 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
        case ilcmt_ws:
          if (*iptr == '\n')
            {
+             pd->line_number++;
              iptr++;
              pd->state = ilcmt_newline;
            }
@@ -251,12 +287,21 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
       
        case ilcmt_copy:
          if ((*optr++ = *iptr++) == '\n')
-           pd->state = ilcmt_newline;
+           {
+             pd->line_number++;
+             pd->state = ilcmt_newline;
+           }
          break;
 
        case ilcmt_comment:
          if (*iptr++ == '\n')
-           pd->state = ilcmt_newline;
+           {
+             pd->line_number++;
+             if (pd->flags & ILCMT_LINE_INFO)
+               pd->state = ilcmt_newline_ac;
+             else
+               pd->state = ilcmt_newline;
+           }
          break;
 
        case ilcmt_rollback_com:
@@ -270,13 +315,13 @@ _ilcmt_decoder (void *xd, enum mu_filter_command cmd,
            {
              *optr++ = ' ';
              pd->state = ilcmt_copy;
+             break;
            }
-         else
-           {
-             *optr++ = pd->buf[pd->replay++];
-             if (pd->replay == pd->level)
-               pd->state = ilcmt_copy;
-           }
+         /* fall through */
+       case ilcmt_rollback:
+         *optr++ = pd->buf[pd->replay++];
+         if (pd->replay == pd->level)
+           pd->state = ilcmt_copy;
        }
     }
   iobuf->isize = iptr - (const unsigned char *) iobuf->input;
@@ -300,8 +345,7 @@ _ilcmt_encoder (void *xd,
       return mu_filter_ok;
       
     case mu_filter_done:
-      free (pd->comment);
-      free (pd->buf);
+      _ilcmt_free (pd);
       return mu_filter_ok;
       
     default:
@@ -353,14 +397,15 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int 
argc, const char **argv)
   struct ilcmt_data *pd = malloc (sizeof (*pd));
   int i;
   const char *comment = ";";
-
+  const char *line_info;
+  
   if (!pd)
     return ENOMEM;
 
-
   pd->flags = 0;
   pd->buf = NULL;
   pd->size = pd->level = pd->replay = 0;
+  pd->line_number = 1;
 
   for (i = 1; i < argc; i++)
     {
@@ -379,7 +424,14 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int 
argc, const char **argv)
            case 'S':
              pd->flags |= ILCMT_FOLLOW_WS;
              break;
-              
+
+           case 'i':
+             pd->flags |= ILCMT_LINE_INFO;
+             if (i + 1 == argc)
+               return MU_ERR_PARSE;
+             line_info = argv[++i];
+             break;
+               
            default:
              free (pd);
              return MU_ERR_PARSE;
@@ -388,13 +440,45 @@ alloc_state (void **pret, int mode MU_ARG_UNUSED, int 
argc, const char **argv)
       else
        comment = argv[i];
     }
-  pd->comment = strdup (comment);
-  if (!pd->comment)
+  if (comment[1] == 0)
+    {
+      pd->sbuf[0] = comment[0];
+      pd->comment = pd->sbuf;
+      pd->flags |= ILCMT_COMMENT_STATIC;
+      pd->length = 1;
+    }
+  else
+    {
+      pd->comment = strdup (comment);
+      if (!pd->comment)
+       {
+         free (pd);
+         return ENOMEM;
+       }
+      pd->length = strlen (comment);
+    }
+
+  if (pd->flags & ILCMT_LINE_INFO)
     {
-      free (pd);
-      return ENOMEM;
+      if (line_info[1] == 0)
+       {
+         pd->sbuf[1] = line_info[0];
+         pd->sbuf[2] = 0;
+         pd->line_info_starter = pd->sbuf + 1;
+         pd->flags |= ILCMT_LINE_INFO_STATIC;
+       }
+      else
+       {
+         pd->line_info_starter = strdup (line_info);
+         if (!pd->line_info_starter)
+           {
+             if (!(pd->flags & ILCMT_COMMENT_STATIC))
+               free (pd->comment);
+             free (pd);
+             return ENOMEM;
+           }
+       }
     }
-  pd->length = strlen (comment);
   
   *pret = pd;
   
diff --git a/libmailutils/filter/linecon.c b/libmailutils/filter/linecon.c
index 35d5101..5c96168 100644
--- a/libmailutils/filter/linecon.c
+++ b/libmailutils/filter/linecon.c
@@ -18,31 +18,70 @@
 
    This filter has only decode mode.  It removes from the input
    backslashes immediately followed by a newline, thus implementing
-   a familiar UNIX line-continuation facility. */
+   a familiar UNIX line-continuation facility.
+
+   The following option is accepted:
+
+      -i STR  Emit line number information after each contiguous sequence
+              of joined lines.  STR supplies "information starter" -- a
+             sequence of characters which is output before the actual line
+             number.
+
+*/
 
 #ifdef HAVE_CONFIG_H
 # include <config.h>
 #endif
 #include <stdlib.h>
+#include <string.h>
 #include <mailutils/errno.h>
 #include <mailutils/filter.h>
 #include <mailutils/cctype.h>
+#include <mailutils/io.h>
+
+#define LINECON_LINE_INFO          0x01 /* Emit line number information */ 
+#define LINECON_LINE_INFO_STATIC   0x02
+
+enum linecon_state
+  {
+    linecon_init,
+    linecon_escape,
+    linecon_newline,
+    linecon_rollback
+  };
+
+struct linecon_data
+{
+  int flags;                 /* Mode flags */
+  enum linecon_state state;  /* Current state */
+  char *line_info_starter;   /* Starter for line number info lines */
+  unsigned long line_number; /* Current line number */
+  char sbuf[2];              /* Static buffer for single-character starters */
+  char *buf;                 /* Rollback buffer ... */
+  size_t size;               /* and its size */
+  size_t level;              /* Number of characters stored in buf. */
+  size_t replay;             /* Index of the next-to-be-replayed character
+                               from buf */
+};
 
 static enum mu_filter_result
 _linecon_decoder (void *xd, enum mu_filter_command cmd,
                  struct mu_filter_io *iobuf)
 {
-  int *escaped = xd;
+  struct linecon_data *pd = xd;
   const unsigned char *iptr, *iend;
   char *optr, *oend;
 
   switch (cmd)
     {
     case mu_filter_init:
-      *escaped = 0;
+      pd->state = linecon_init;
       return mu_filter_ok;
       
     case mu_filter_done:
+      if ((pd->flags & LINECON_LINE_INFO) &&
+         !(pd->flags & LINECON_LINE_INFO_STATIC))
+       free (pd->line_info_starter);
       return mu_filter_ok;
       
     default:
@@ -56,34 +95,57 @@ _linecon_decoder (void *xd, enum mu_filter_command cmd,
 
   while (iptr < iend && optr < oend)
     {
-      int c = *iptr++;
-      switch (c)
+      switch (pd->state)
        {
-       case '\\':
-         *escaped = 1;
-         continue;
-
-       case '\n':
-         if (*escaped)
+       case linecon_init:
+       case linecon_newline:
+         switch (*iptr)
            {
-             *escaped = 0;
+           case '\\':
+             iptr++;
+             pd->state = linecon_escape;
              continue;
+           case '\n':
+             pd->line_number++;
+             if (pd->state == linecon_newline)
+               {
+                 mu_asnprintf (&pd->buf, &pd->size, "%s %lu\n",
+                               pd->line_info_starter,
+                               pd->line_number);
+                 pd->level = strlen (pd->buf);
+                 pd->replay = 0;
+                 pd->state = linecon_rollback;
+               }
+             /* fall through */
+           default:
+             *optr++ = *iptr++;
+             break;
            }
-         *optr++ = c;
          break;
 
-       default:
-         if (*escaped)
+       case linecon_escape:
+         if (*iptr == '\n')
+           {
+             pd->line_number++;
+             iptr++;
+             pd->state = (pd->flags & LINECON_LINE_INFO) ?
+                            linecon_newline : linecon_init;
+             continue;
+           }
+         else
            {
-             *escaped = 0;
+             pd->state = linecon_init;
              *optr++ = '\\';
              if (optr == oend)
-               {
-                 iptr--;
-                 break;
-               }
+               break;
+             *optr++ = *iptr++;
            }
-         *optr++ = c;
+         break;
+         
+       case linecon_rollback:
+         *optr++ = pd->buf[pd->replay++];
+         if (pd->replay == pd->level)
+           pd->state = linecon_init;
        }
     }
 
@@ -95,9 +157,55 @@ _linecon_decoder (void *xd, enum mu_filter_command cmd,
 static int
 alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv)
 {
-  *pret = malloc (sizeof (int));
-  if (!*pret)
+  int i;
+  struct linecon_data *pd = malloc (sizeof (pd[0]));
+  const char *line_info;
+  
+  if (!pd)
     return ENOMEM;
+  pd->flags = 0;
+  pd->buf = NULL;
+  pd->size = pd->level = pd->replay = 0;
+  pd->line_number = 1;
+  for (i = 1; i < argc; i++)
+    {
+      if (argv[i][0] == '-')
+       {
+         switch (argv[i][1])
+           {
+           case 'i':
+             pd->flags |= LINECON_LINE_INFO;
+             if (i + 1 == argc)
+               return MU_ERR_PARSE;
+             line_info = argv[++i];
+             break;
+             
+           default:
+             free (pd);
+             return MU_ERR_PARSE;
+           }
+       }
+    }
+  if (pd->flags & LINECON_LINE_INFO)
+    {
+      if (line_info[1])
+       {
+         pd->line_info_starter = strdup (line_info);
+         if (!pd->line_info_starter)
+           {
+             free (pd);
+             return ENOMEM;
+           }
+       }
+      else
+       {
+         pd->sbuf[0] = line_info[0];
+         pd->sbuf[1] = 0;
+         pd->line_info_starter = pd->sbuf;
+         pd->flags |= LINECON_LINE_INFO_STATIC;
+       }
+    }
+  *pret = pd;
   return 0;
 }
 
diff --git a/libmailutils/stream/logstream.c b/libmailutils/stream/logstream.c
index 67b56e2..aa4a7d0 100644
--- a/libmailutils/stream/logstream.c
+++ b/libmailutils/stream/logstream.c
@@ -257,17 +257,14 @@ static void
 _log_done (struct _mu_stream *str)
 {
   struct _mu_log_stream *sp = (struct _mu_log_stream *)str;
-  if (str->flags & MU_STREAM_AUTOCLOSE)
-    mu_stream_destroy (&sp->transport);
+  mu_stream_destroy (&sp->transport);
 }
 
 static int
 _log_close (struct _mu_stream *str)
 {
   struct _mu_log_stream *sp = (struct _mu_log_stream *)str;
-  if (str->flags & MU_STREAM_AUTOCLOSE)
-    return mu_stream_close (sp->transport);
-  return 0;
+  return mu_stream_close (sp->transport);
 }
 
 static int


hooks/post-receive
-- 
GNU Mailutils



reply via email to

[Prev in Thread] Current Thread [Next in Thread]