]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
Add %%, %^%, %comment%, %control C%, %text T% formatting directives.
authorBen Schmidt <none@none>
Mon, 16 Jan 2012 10:29:17 +0000 (21:29 +1100)
committerBen Schmidt <none@none>
Mon, 16 Jan 2012 10:29:17 +0000 (21:29 +1100)
To support inclusion, use a stack of sources when reading list texts.

ChangeLog
README.listtexts
src/prepstdreply.c

index 5eb9060acbceb9586b3fb6441124e1f0d0bda57c..e8f526399cd49bf1ec16d802592c4ed021f46f7d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+ o Add %%, %^%, %comment%, %control C% and %text T% formatting directives
  o Allow a space in $originalmail N$ substitution
  o Improve algorithm for list text substitutions
  o Add $text T$ substitution
index 5abc727f652976a0463592b2c068d452da50f9b6..b7c0f82321495f624d365e4c78300429f09960fc 100644 (file)
@@ -289,16 +289,27 @@ not appropriate for use in headers. They are:
   the list of indexes of messages which may not have been received as they
   bounced
 
+- %^%
+  start the line here; anything preceding this directive is ignored (useful for
+  using indentation for readability without ruining the formatting of the text
+  when it is processed)
+
 - %comment%
-  the rest of the line is a comment
+- %$%
+  end the line here; anything following this directive is ignored
 
 - %%
   a single %
 
-All these directives have the behaviour that second and later lines are
-preceded with as many spaces as there were characters preceding the directive
-in the processed output. All of them except %wrap% and %wrap W% cause anything
-following them on the same line to be omitted.
+Directives which include a list of items have the behaviour that each item is
+preceded and followed by the same text as preceded and followed the directive
+on its line. Only one such directive is supported per line.
+
+The %wrap% and %wrap W% directives, as well as those which include a block of
+text, have the behaviour that second and later lines are preceded with as many
+spaces as there were characters preceding the directive. Apart from the
+%wrap% and %wrap W% directives, any text following the directive on the same
+line is omitted.
 
 If a line with any of these directives, after processing, contains only
 whitespace, the line does not appear at all in the output (the newline and any
index fb818d89ffb4f46e4b5767a23acb0221f60fb4f2..3c777599c03e16e9679ee8d128292fdaa3e0489b 100644 (file)
 #include "unistr.h"
 
 
-struct text {
+struct source;
+typedef struct source source;
+struct source {
+       source *prev;
+       char *upcoming;
+       char *prefix;
+       char *suffix;
        int fd;
 };
 
 
+struct text {
+       source *src;
+};
+
+
 static char *alphanum_token(char *token) {
        char *pos;
        if (*token == '\0') return NULL;
@@ -197,21 +208,26 @@ text *open_text_file(const char *listdir, const char *filename)
        text *txt;
 
        txt = mymalloc(sizeof(text));
+       txt->src = mymalloc(sizeof(source));
+       txt->src->prev = NULL;
+       txt->src->upcoming = NULL;
+       txt->src->prefix = NULL;
+       txt->src->suffix = NULL;
 
        tmp = concatstr(3, listdir, "/text/", filename);
-       txt->fd = open(tmp, O_RDONLY);
+       txt->src->fd = open(tmp, O_RDONLY);
        myfree(tmp);
-       if (txt->fd >= 0) return txt;
+       if (txt->src->fd >= 0) return txt;
 
        tmp = concatstr(2, DEFAULTTEXTDIR "/default/", filename);
-       txt->fd = open(tmp, O_RDONLY);
+       txt->src->fd = open(tmp, O_RDONLY);
        myfree(tmp);
-       if (txt->fd >= 0) return txt;
+       if (txt->src->fd >= 0) return txt;
 
        tmp = concatstr(2, DEFAULTTEXTDIR "/en/", filename);
-       txt->fd = open(tmp, O_RDONLY);
+       txt->src->fd = open(tmp, O_RDONLY);
        myfree(tmp);
-       if (txt->fd >= 0) return txt;
+       if (txt->src->fd >= 0) return txt;
 
        return NULL;
 }
@@ -257,32 +273,205 @@ text *open_text(const char *listdir, const char *purpose, const char *action,
 }
 
 
+static void begin_new_source_file(text *txt, char **line_p, char **pos_p,
+               const char *filename) {
+       char *line = *line_p;
+       char *pos = *pos_p;
+       char *tmp;
+       source *src;
+       int fd;
+       size_t len;
+
+       /* Save any later lines for use after finishing the source */
+       while (*pos != '\0' && *pos != '\r' && *pos != '\n') pos++;
+       if (*pos == '\r') pos++;
+       if (*pos == '\n') pos++;
+       if (*pos != '\0') txt->src->upcoming = mystrdup(pos);
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               /* Act as if the source were an empty line */
+               **pos_p = '\0';
+               return;
+       }
+
+       src = mymalloc(sizeof(source));
+       src->prev = txt->src;
+       src->upcoming = NULL;
+       len = strlen(line);
+       src->prefix = mymalloc((len + 1) * sizeof(char));
+       for (tmp = src->prefix; len > 0; ++tmp, --len) *tmp = ' ';
+       *tmp = '\0';
+       src->suffix = NULL;
+       src->fd = fd;
+       txt->src = src;
+       tmp = mygetline(fd);
+       line = concatstr(2, line, tmp);
+       *pos_p = line + (*pos_p - *line_p);
+       myfree(*line_p);
+       *line_p = line;
+       myfree(tmp);
+}
+
+
+static void handle_directive(text *txt, char **line_p, char **pos_p,
+               const char *listdir) {
+       char *line = *line_p;
+       char *pos = *pos_p;
+       char *token = pos + 1;
+       char *endpos;
+       char *filename;
+
+       endpos = strchr(token, '%');
+       if (endpos == NULL) {
+               (*pos_p)++;
+               return;
+       }
+
+       *pos = '\0';
+       *endpos = '\0';
+
+       if(strcmp(token, "") == 0) {
+               line = concatstr(3, line, "%", endpos + 1);
+               *pos_p = line + (*pos_p - *line_p) + 1;
+               myfree(*line_p);
+               *line_p = line;
+               return;
+       } else if(strcmp(token, "^") == 0) {
+               if (txt->src->prefix != NULL) {
+                       line[strlen(txt->src->prefix)] = '\0';
+                       line = concatstr(2, line, endpos + 1);
+               } else {
+                       line = mystrdup(endpos + 1);
+               }
+               *pos_p = line;
+               myfree(*line_p);
+               *line_p = line;
+               return;
+       } else if(strcmp(token, "comment") == 0 || strcmp(token, "$") == 0 ) {
+               /* Skip the rest of the line; the earlier part which we
+                * will return has already been truncated; the caller
+                * will save the next line for later use if necessary. */
+               pos = endpos + 1;
+               while (*pos != '\0' && *pos != '\r' && *pos != '\n') pos++;
+               *pos_p = pos;
+               return;
+       } else if(strncmp(token, "control ", 8) == 0) {
+               token = alphanum_token(token + 8);
+               if (token != NULL) {
+                       filename = concatstr(3, listdir, "/control/", token);
+                       begin_new_source_file(txt, line_p, pos_p, filename);
+                       myfree(filename);
+                       return;
+               }
+       } else if(strncmp(token, "text ", 5) == 0) {
+               token = alphanum_token(token + 5);
+               if (token != NULL) {
+                       filename = concatstr(3, listdir, "/text/", token);
+                       begin_new_source_file(txt, line_p, pos_p, filename);
+                       myfree(filename);
+                       return;
+               }
+       }
+       if (token == NULL) {
+               /* We have encountered a directive, but not been able to deal
+                * with it, so just advance through the string. */
+               *pos = '%';
+               *endpos = '%';
+               (*pos_p)++;
+               return;
+       }
+
+       /* No recognised directive; just advance through the string. */
+       *pos = '%';
+       *endpos = '%';
+       (*pos_p)++;
+       return;
+}
+
+
 char *get_processed_text_line(text *txt,
                const char *listaddr, const char *listdelim,
                size_t datacount, char **data, const char *listdir)
 {
-       char *line;
+       char *line = NULL;
+       char *pos;
        char *tmp;
-       char *retstr;
+       source *src;
 
-       line = mygetline(txt->fd);
+       while (txt->src != NULL) {
+               if (txt->src->upcoming != NULL) {
+                       if (txt->src->prefix != NULL) {
+                               line = concatstr(2, txt->src->prefix, txt->src->upcoming);
+                               myfree(txt->src->upcoming);
+                       } else {
+                               line = txt->src->upcoming;
+                       }
+                       txt->src->upcoming = NULL;
+                       break;
+               }
+               txt->src->upcoming = mygetline(txt->src->fd);
+               if (txt->src->upcoming != NULL) continue;
+               close(txt->src->fd);
+               src = txt->src;
+               txt->src = txt->src->prev;
+               myfree(src);
+       }
        if (line == NULL) return NULL;
 
-       chomp(line);
-
        tmp = unistr_escaped_to_utf8(line);
        myfree(line);
+       line = tmp;
 
-       retstr = substitute(tmp, listaddr, listdelim,
-                        datacount, data, listdir);
-       myfree(tmp);
+       pos = line;
+       while (*pos != '\0') {
+               if (*pos == '\r') {
+                       *pos = '\0';
+                       pos++;
+                       if (*pos == '\n') pos++;
+                       if (*pos == '\0') break;
+                       txt->src->upcoming = mystrdup(pos);
+                       break;
+               } else if (*pos == '\n') {
+                       *pos = '\0';
+                       pos++;
+                       if (*pos == '\0') break;
+                       txt->src->upcoming = mystrdup(pos);
+                       break;
+               } else if (*pos == '$') {
+                       substitute_one(&line, &pos,
+                                       listaddr, listdelim,
+                                       datacount, data, listdir);
+                       /* The function sets up for the next character
+                        * to process, so continue straight away. */
+                       continue;
+               } else if (*pos == '%') {
+                       handle_directive(txt, &line, &pos, listdir);
+                       /* The function sets up for the next character
+                        * to process, so continue straight away. */
+                       continue;
+               }
+               pos++;
+       }
 
-       return retstr;
+       if (txt->src->suffix != NULL) {
+               tmp = concatstr(2, line, txt->src->suffix);
+               myfree(line);
+               return tmp;
+       } else {
+               return line;
+       }
 }
 
 
 void close_text(text *txt) {
-       close(txt->fd);
+       source *tmp;
+       while (txt->src != NULL) {
+               close(txt->src->fd);
+               tmp = txt->src;
+               txt->src = txt->src->prev;
+               myfree(tmp);
+       }
 }