Implement the following changes:
authorPaul Fox <pgf@foxharp.boston.ma.us>
Thu, 31 May 2012 19:15:36 +0000 (15:15 -0400)
committerKen Hornstein <kenh@pobox.com>
Thu, 31 May 2012 19:15:36 +0000 (15:15 -0400)
- Special #on/#off/#pop directives to control the MIME directive
  processing state
- A flag (-directives) to control whether or not mhbuild will honor MIME
  directives by default.

man/mhbuild.man
uip/mhbuild.c
uip/mhbuildsbr.c

index cd7e7fd..d127de8 100644 (file)
@@ -12,6 +12,7 @@ mhbuild \- translate MIME composition draft
 .RB [ \-list " | " \-nolist ]
 .RB [ \-realsize " | " \-norealsize ]
 .RB [ \-headers " | " \-noheaders ]
+.RB [ \-directives " | " \-nodirectives ]
 .RB [ \-ebcdicsafe " | " \-noebcdicsafe ]
 .RB [ \-rfc934mode " | " \-norfc934mode ]
 .RB [ \-contentid " | " \-nocontentid ]
@@ -115,12 +116,36 @@ than one line, e.g.,
 .fi
 .RE
 .PP
-There are four kinds of directives: \*(lqtype\*(rq directives, which
+There are five kinds of directives: \*(lqtype\*(rq directives, which
 name the type and subtype of the content; \*(lqexternal-type\*(rq
 directives, which also name the type and subtype of the content; the
 \*(lqmessage\*(rq directive (#forw), which is used to forward one or
-more messages; and, the \*(lqbegin\*(rq directive (#begin), which is
-used to create a multipart content.
+more messages; the \*(lqbegin\*(rq directive (#begin), which is
+used to create a multipart content; and the \*(lqon/off/pop\*(rq
+directives (#on, #off, #pop) which control whether any other
+directives are honored at all.
+.PP
+The
+.B \-directives
+switch allows control over whether mhbuild will honor any of the
+\*(lq#\*(rq-directives.  This can also be affected with the #on or
+#off directives, and #pop, which restores the state of processing to
+that preceding the most recent #on or #off.  (The #on, #off, and #pop
+directives are always honored, of course.) This allows inclusion of
+plain text which looks like mhbuild directives, without causing
+errors:
+.PP
+.RS 5
+.nf
+#off
+#include <stdio.h>
+
+printf("Hello, World!);
+#pop
+.fi
+.RE
+.PP
+Currently the stack depth for the #on/off/pop directives is 32.
 .PP
 The \*(lqtype\*(rq directive is used to directly specify the type and
 subtype of a content.  You may only specify discrete types in this manner
index ad674f4..020512d 100644 (file)
@@ -25,43 +25,47 @@ static struct swit switches[] = {
     { "check", 0 },
 #define        NCHECKSW                1
     { "nocheck", 0 },
-#define        EBCDICSW                2
+#define        DIRECTIVES              2
+    { "directives", 0 },
+#define        NDIRECTIVES             3
+    { "nodirectives", 0 },
+#define        EBCDICSW                4
     { "ebcdicsafe", 0 },
-#define        NEBCDICSW               3
+#define        NEBCDICSW               5
     { "noebcdicsafe", 0 },
-#define        HEADSW                  4
+#define        HEADSW                  6
     { "headers", 0 },
-#define        NHEADSW                 5
+#define        NHEADSW                 7
     { "noheaders", 0 },
-#define        LISTSW                  6
+#define        LISTSW                  8
     { "list", 0 },
-#define        NLISTSW                 7
+#define        NLISTSW                 9
     { "nolist", 0 },
-#define        SIZESW                  8
+#define        SIZESW                 10
     { "realsize", 0 },
-#define        NSIZESW                 9
+#define        NSIZESW                11
     { "norealsize", 0 },
-#define        RFC934SW               10
+#define        RFC934SW               12
     { "rfc934mode", 0 },
-#define        NRFC934SW              11
+#define        NRFC934SW              13
     { "norfc934mode", 0 },
-#define        VERBSW                 12
+#define        VERBSW                 14
     { "verbose", 0 },
-#define        NVERBSW                13
+#define        NVERBSW                15
     { "noverbose", 0 },
-#define        RCACHESW               14
+#define        RCACHESW               16
     { "rcache policy", 0 },
-#define        WCACHESW               15
+#define        WCACHESW               17
     { "wcache policy", 0 },
-#define        CONTENTIDSW            16
+#define        CONTENTIDSW            18
     { "contentid", 0 },
-#define        NCONTENTIDSW           17
+#define        NCONTENTIDSW           19
     { "nocontentid", 0 },
-#define VERSIONSW              18
+#define VERSIONSW              20
     { "version", 0 },
-#define        HELPSW                 19
+#define        HELPSW                 21
     { "help", 0 },
-#define        DEBUGSW                20
+#define        DEBUGSW                22
     { "debug", -5 },
     { NULL, 0 }
 };
@@ -96,7 +100,7 @@ static int unlink_outfile = 0;
 static void unlink_done (int) NORETURN;
 
 /* mhbuildsbr.c */
-CT build_mime (char *);
+CT build_mime (char *, int);
 int output_message (CT, char *);
 int output_message_fp (CT, FILE *, char*);
 
@@ -110,7 +114,7 @@ void free_content (CT);
 int
 main (int argc, char **argv)
 {
-    int sizesw = 1, headsw = 1;
+    int sizesw = 1, headsw = 1, directives = 1;
     int *icachesw;
     char *cp, buf[BUFSIZ];
     char buffer[BUFSIZ], *compfile = NULL;
@@ -198,6 +202,13 @@ main (int argc, char **argv)
                headsw = 0;
                continue;
 
+           case DIRECTIVES:
+               directives = 1;
+               continue;
+           case NDIRECTIVES:
+               directives = 0;
+               continue;
+
            case LISTSW:
                listsw++;
                continue;
@@ -306,7 +317,7 @@ main (int argc, char **argv)
        unlink_infile = 1;
 
        /* build the content structures for MIME message */
-       ct = build_mime (infile);
+       ct = build_mime (infile, directives);
        cts[0] = ct;
        cts[1] = NULL;
 
@@ -340,7 +351,7 @@ main (int argc, char **argv)
      */
 
     /* build the content structures for MIME message */
-    ct = build_mime (compfile);
+    ct = build_mime (compfile, directives);
     cts[0] = ct;
     cts[1] = NULL;
 
index fd6a974..93f1647 100644 (file)
@@ -72,7 +72,7 @@ void free_encoding (CT, int);
 /*
  * prototypes
  */
-CT build_mime (char *);
+CT build_mime (char *, int);
 
 /*
  * static prototypes
@@ -87,6 +87,37 @@ static int build_headers (CT);
 static char *calculate_digest (CT, int);
 
 
+static unsigned char directives_stack[32];
+static unsigned int directives_index;
+
+static int do_direct(void)
+{
+    return directives_stack[directives_index];
+}
+
+static void directive_onoff(int onoff)
+{
+    if (directives_index >= sizeof(directives_stack)) {
+       fprintf(stderr, "mhbuild: #on/off overflow, continuing\n");
+       return;
+    }
+    directives_stack[++directives_index] = onoff;
+}
+
+static void directive_init(int onoff)
+{
+    directives_index = 0;
+    directives_stack[0] = onoff;
+}
+
+static void directive_pop(void)
+{
+    if (directives_index > 0)
+       directives_index--;
+    else
+       fprintf(stderr, "mhbuild: #pop underflow, continuing\n");
+}
+
 /*
  * Main routine for translating composition file
  * into valid MIME message.  It translates the draft
@@ -97,7 +128,7 @@ static char *calculate_digest (CT, int);
  */
 
 CT
-build_mime (char *infile)
+build_mime (char *infile, int directives)
 {
     int        compnum, state;
     char buf[BUFSIZ], name[NAMESZ];
@@ -107,6 +138,8 @@ build_mime (char *infile)
     CT ct;
     FILE *in;
 
+    directive_init(directives);
+
     umask (~m_gmprot ());
 
     /* open the composition draft */
@@ -327,20 +360,34 @@ static char *
 fgetstr (char *s, int n, FILE *stream)
 {
     char *cp, *ep;
+    int o_n = n;
+
+    while(1) {
+       for (ep = (cp = s) + o_n; cp < ep; ) {
+           int i;
 
-    for (ep = (cp = s) + n; cp < ep; ) {
-       int i;
+           if (!fgets (cp, n, stream))
+               return (cp != s ? s : NULL);
 
-       if (!fgets (cp, n, stream))
-           return (cp != s ? s : NULL);
-       if (cp == s && *cp != '#')
-           return s;
+           if (cp == s && *cp != '#')
+               return s;
 
-       cp += (i = strlen (cp)) - 1;
-       if (i <= 1 || *cp-- != '\n' || *cp != '\\')
+           cp += (i = strlen (cp)) - 1;
+           if (i <= 1 || *cp-- != '\n' || *cp != '\\')
+               break;
+           *cp = '\0';
+           n -= (i - 2);
+       }
+
+       if (strcmp(s, "#on\n") == 0) {
+           directive_onoff(1);
+       } else if (strcmp(s, "#off\n") == 0) {
+           directive_onoff(0);
+       } else if (strcmp(s, "#pop\n") == 0) {
+           directive_pop();
+       } else {
            break;
-       *cp = '\0';
-       n -= (i - 2);
+       }
     }
 
     return s;
@@ -367,7 +414,7 @@ user_content (FILE *in, char *file, char *buf, CT *ctp)
     CT ct;
     CE ce;
 
-    if (buf[0] == '\n' || strcmp (buf, "#\n") == 0) {
+    if (buf[0] == '\n' || (do_direct() && strcmp (buf, "#\n") == 0)) {
        *ctp = NULL;
        return OK;
     }
@@ -392,7 +439,7 @@ user_content (FILE *in, char *file, char *buf, CT *ctp)
      * 2) begins with "##"             (implicit directive)
      * 3) begins with "#<"
      */
-    if (buf[0] != '#' || buf[1] == '#' || buf[1] == '<') {
+    if (!do_direct() || buf[0] != '#' || buf[1] == '#' || buf[1] == '<') {
        int headers;
        int inlineD;
        long pos;
@@ -407,7 +454,7 @@ user_content (FILE *in, char *file, char *buf, CT *ctp)
        ce->ce_file = add (cp, NULL);
        ce->ce_unlink = 1;
 
-       if (buf[0] == '#' && buf[1] == '<') {
+       if (do_direct() && (buf[0] == '#' && buf[1] == '<')) {
            strncpy (content, buf + 2, sizeof(content));
            inlineD = 1;
            goto rock_and_roll;
@@ -418,11 +465,11 @@ user_content (FILE *in, char *file, char *buf, CT *ctp)
        /* the directive is implicit */
        strncpy (content, "text/plain", sizeof(content));
        headers = 0;
-       strncpy (buffer, buf[0] != '#' ? buf : buf + 1, sizeof(buffer));
+       strncpy (buffer, (!do_direct() || buf[0] != '#') ? buf : buf + 1, sizeof(buffer));
        for (;;) {
            int i;
 
-           if (headers >= 0 && uprf (buffer, DESCR_FIELD)
+           if (headers >= 0 && do_direct() && uprf (buffer, DESCR_FIELD)
                && buffer[i = strlen (DESCR_FIELD)] == ':') {
                headers = 1;
 
@@ -445,7 +492,7 @@ again_descr:
                }
            }
 
-           if (headers >= 0 && uprf (buffer, DISPO_FIELD)
+           if (headers >= 0 && do_direct() && uprf (buffer, DISPO_FIELD)
                && buffer[i = strlen (DISPO_FIELD)] == ':') {
                headers = 1;
 
@@ -476,7 +523,7 @@ rock_and_roll:
            pos = ftell (in);
            if ((cp = fgetstr (buffer, sizeof(buffer) - 1, in)) == NULL)
                break;
-           if (buffer[0] == '#') {
+           if (do_direct() && buffer[0] == '#') {
                char *bp;
 
                if (buffer[1] != '#')