<p>Sean Bright has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16623">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_playback.c: Remove experimental 'say' application<br><br>ASTERISK-29695 #close<br><br>Change-Id: I3200aa184d97679e4a134ec1de82389203d2a0de<br>---<br>M apps/app_playback.c<br>D configs/samples/say.conf.sample<br>2 files changed, 2 insertions(+), 801 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/23/16623/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_playback.c b/apps/app_playback.c</span><br><span>index 0c9281a..e3531a9 100644</span><br><span>--- a/apps/app_playback.c</span><br><span>+++ b/apps/app_playback.c</span><br><span>@@ -35,11 +35,6 @@</span><br><span> #include "asterisk/pbx.h"</span><br><span> #include "asterisk/module.h"</span><br><span> #include "asterisk/app.h"</span><br><span style="color: hsl(0, 100%, 40%);">-/* This file provides config-file based 'say' functions, and implenents</span><br><span style="color: hsl(0, 100%, 40%);">- * some CLI commands.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/say.h"      /*!< provides config-file based 'say' functions */</span><br><span style="color: hsl(0, 100%, 40%);">-#include "asterisk/cli.h"</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span>   <application name="Playback" language="en_US"></span><br><span>@@ -93,359 +88,12 @@</span><br><span> </span><br><span> static char *app = "Playback";</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_config *say_cfg = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief save the say' api calls.</span><br><span style="color: hsl(0, 100%, 40%);">- * The first entry is NULL if we have the standard source,</span><br><span style="color: hsl(0, 100%, 40%);">- * otherwise we are sourcing from here.</span><br><span style="color: hsl(0, 100%, 40%);">- * 'say load [new|old]' will enable the new or old method, or report status</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-static const void *say_api_buf[40];</span><br><span style="color: hsl(0, 100%, 40%);">-static const char * const say_old = "old";</span><br><span style="color: hsl(0, 100%, 40%);">-static const char * const say_new = "new";</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void save_say_mode(const void *arg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        int i = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-      say_api_buf[i++] = arg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- say_api_buf[i++] = ast_say_number_full;</span><br><span style="color: hsl(0, 100%, 40%);">- say_api_buf[i++] = ast_say_enumeration_full;</span><br><span style="color: hsl(0, 100%, 40%);">-    say_api_buf[i++] = ast_say_digit_str_full;</span><br><span style="color: hsl(0, 100%, 40%);">-      say_api_buf[i++] = ast_say_character_str_full;</span><br><span style="color: hsl(0, 100%, 40%);">-  say_api_buf[i++] = ast_say_phonetic_str_full;</span><br><span style="color: hsl(0, 100%, 40%);">-   say_api_buf[i++] = ast_say_datetime;</span><br><span style="color: hsl(0, 100%, 40%);">-    say_api_buf[i++] = ast_say_time;</span><br><span style="color: hsl(0, 100%, 40%);">-        say_api_buf[i++] = ast_say_date;</span><br><span style="color: hsl(0, 100%, 40%);">-        say_api_buf[i++] = ast_say_datetime_from_now;</span><br><span style="color: hsl(0, 100%, 40%);">-   say_api_buf[i++] = ast_say_date_with_format;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static void restore_say_mode(void *arg)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-   int i = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-      say_api_buf[i++] = arg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ast_say_number_full = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">- ast_say_enumeration_full = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-    ast_say_digit_str_full = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_say_character_str_full = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-  ast_say_phonetic_str_full = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-   ast_say_datetime = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-    ast_say_time = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-        ast_say_date = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-        ast_say_datetime_from_now = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-   ast_say_date_with_format = say_api_buf[i++];</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief</span><br><span style="color: hsl(0, 100%, 40%);">- * Typical 'say' arguments in addition to the date or number or string</span><br><span style="color: hsl(0, 100%, 40%);">- * to say. We do not include 'options' because they may be different</span><br><span style="color: hsl(0, 100%, 40%);">- * in recursive calls, and so they are better left as an external</span><br><span style="color: hsl(0, 100%, 40%);">- * parameter.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-typedef struct {</span><br><span style="color: hsl(0, 100%, 40%);">-      struct ast_channel *chan;</span><br><span style="color: hsl(0, 100%, 40%);">-       const char *ints;</span><br><span style="color: hsl(0, 100%, 40%);">-       const char *language;</span><br><span style="color: hsl(0, 100%, 40%);">-   int audiofd;</span><br><span style="color: hsl(0, 100%, 40%);">-    int ctrlfd;</span><br><span style="color: hsl(0, 100%, 40%);">-} say_args_t;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int s_streamwait3(const say_args_t *a, const char *fn)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  int res = ast_streamfile(a->chan, fn, a->language);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (res) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_WARNING, "Unable to play message %s\n", fn);</span><br><span style="color: hsl(0, 100%, 40%);">-              return res;</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-       res = (a->audiofd  > -1 && a->ctrlfd > -1) ?</span><br><span style="color: hsl(0, 100%, 40%);">-        ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_waitstream(a->chan, a->ints);</span><br><span style="color: hsl(0, 100%, 40%);">- ast_stopstream(a->chan);</span><br><span style="color: hsl(0, 100%, 40%);">-     return res;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief</span><br><span style="color: hsl(0, 100%, 40%);">- * the string is 'prefix:data' or prefix:fmt:data'</span><br><span style="color: hsl(0, 100%, 40%);">- * with ':' being invalid in strings.</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-static int do_say(say_args_t *a, const char *s, const char *options, int depth)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct ast_variable *v;</span><br><span style="color: hsl(0, 100%, 40%);">- char *lang;</span><br><span style="color: hsl(0, 100%, 40%);">-     char *x;</span><br><span style="color: hsl(0, 100%, 40%);">-        char *rule = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-      char *rule_head = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- int ret = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct varshead head = { .first = NULL, .last = NULL };</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_var_t *n;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    ast_debug(2, "string <%s> depth <%d>\n", s, depth);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (depth++ > 10) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_log(LOG_WARNING, "recursion too deep, exiting\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      } else if (!say_cfg) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);</span><br><span style="color: hsl(0, 100%, 40%);">-          return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* scan languages same as in file.c */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (a->language == NULL)</span><br><span style="color: hsl(0, 100%, 40%);">-             a->language = "en";     /* default */</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_debug(2, "try <%s> in <%s>\n", s, a->language);</span><br><span style="color: hsl(0, 100%, 40%);">-    lang = ast_strdupa(a->language);</span><br><span style="color: hsl(0, 100%, 40%);">-     for (;;) {</span><br><span style="color: hsl(0, 100%, 40%);">-              for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {</span><br><span style="color: hsl(0, 100%, 40%);">-                      if (ast_extension_match(v->name, s)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                               rule_head = rule = ast_strdup(v->value);</span><br><span style="color: hsl(0, 100%, 40%);">-                             break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (rule)</span><br><span style="color: hsl(0, 100%, 40%);">-                       break;</span><br><span style="color: hsl(0, 100%, 40%);">-          if ( (x = strchr(lang, '_')) )</span><br><span style="color: hsl(0, 100%, 40%);">-                  *x = '\0';      /* try without suffix */</span><br><span style="color: hsl(0, 100%, 40%);">-                else if (strcmp(lang, "en"))</span><br><span style="color: hsl(0, 100%, 40%);">-                  lang = "en";    /* last resort, try 'en' if not done yet */</span><br><span style="color: hsl(0, 100%, 40%);">-           else</span><br><span style="color: hsl(0, 100%, 40%);">-                    break;</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!rule)</span><br><span style="color: hsl(0, 100%, 40%);">-              return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* skip up to two prefixes to get the value */</span><br><span style="color: hsl(0, 100%, 40%);">-  if ( (x = strchr(s, ':')) )</span><br><span style="color: hsl(0, 100%, 40%);">-             s = x + 1;</span><br><span style="color: hsl(0, 100%, 40%);">-      if ( (x = strchr(s, ':')) )</span><br><span style="color: hsl(0, 100%, 40%);">-             s = x + 1;</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_debug(2, "value is <%s>\n", s);</span><br><span style="color: hsl(0, 100%, 40%);">-     n = ast_var_assign("SAY", s);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!n) {</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_log(LOG_ERROR, "Memory allocation error in do_say\n");</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_free(rule_head);</span><br><span style="color: hsl(0, 100%, 40%);">-            return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       AST_LIST_INSERT_HEAD(&head, n, entries);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* scan the body, one piece at a time */</span><br><span style="color: hsl(0, 100%, 40%);">-        while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */</span><br><span style="color: hsl(0, 100%, 40%);">-            char fn[128];</span><br><span style="color: hsl(0, 100%, 40%);">-           const char *p, *fmt, *data; /* format and data pointers */</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-              /* prepare a decent file name */</span><br><span style="color: hsl(0, 100%, 40%);">-                x = ast_skip_blanks(x);</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_trim_blanks(x);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             /* replace variables */</span><br><span style="color: hsl(0, 100%, 40%);">-         pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_debug(2, "doing [%s]\n", fn);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-             /* locate prefix and data, if any */</span><br><span style="color: hsl(0, 100%, 40%);">-            fmt = strchr(fn, ':');</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!fmt || fmt == fn)  {       /* regular filename */</span><br><span style="color: hsl(0, 100%, 40%);">-                  ret = s_streamwait3(a, fn);</span><br><span style="color: hsl(0, 100%, 40%);">-                     continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               fmt++;</span><br><span style="color: hsl(0, 100%, 40%);">-          data = strchr(fmt, ':');        /* colon before data */</span><br><span style="color: hsl(0, 100%, 40%);">-         if (!data || data == fmt) {     /* simple prefix-fmt */</span><br><span style="color: hsl(0, 100%, 40%);">-                 ret = do_say(a, fn, options, depth);</span><br><span style="color: hsl(0, 100%, 40%);">-                    continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               /* prefix:fmt:data */</span><br><span style="color: hsl(0, 100%, 40%);">-           for (p = fmt; p < data && ret <= 0; p++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        char fn2[sizeof(fn)];</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (*p == ' ' || *p == '\t')    /* skip blanks */</span><br><span style="color: hsl(0, 100%, 40%);">-                               continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (*p == '\'') {/* file name - we trim them */</span><br><span style="color: hsl(0, 100%, 40%);">-                             char *y;</span><br><span style="color: hsl(0, 100%, 40%);">-                                strcpy(fn2, ast_skip_blanks(p+1));      /* make a full copy */</span><br><span style="color: hsl(0, 100%, 40%);">-                          y = strchr(fn2, '\'');</span><br><span style="color: hsl(0, 100%, 40%);">-                              if (!y) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                       p = data;       /* invalid. prepare to end */</span><br><span style="color: hsl(0, 100%, 40%);">-                                   break;</span><br><span style="color: hsl(0, 100%, 40%);">-                          }</span><br><span style="color: hsl(0, 100%, 40%);">-                               *y = '\0';</span><br><span style="color: hsl(0, 100%, 40%);">-                              ast_trim_blanks(fn2);</span><br><span style="color: hsl(0, 100%, 40%);">-                           p = strchr(p+1, '\'');</span><br><span style="color: hsl(0, 100%, 40%);">-                              ret = s_streamwait3(a, fn2);</span><br><span style="color: hsl(0, 100%, 40%);">-                    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                int l = fmt-fn;</span><br><span style="color: hsl(0, 100%, 40%);">-                         strcpy(fn2, fn); /* copy everything */</span><br><span style="color: hsl(0, 100%, 40%);">-                          /* after prefix, append the format */</span><br><span style="color: hsl(0, 100%, 40%);">-                           fn2[l++] = *p;</span><br><span style="color: hsl(0, 100%, 40%);">-                          strcpy(fn2 + l, data);</span><br><span style="color: hsl(0, 100%, 40%);">-                          ret = do_say(a, fn2, options, depth);</span><br><span style="color: hsl(0, 100%, 40%);">-                   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (ret) {</span><br><span style="color: hsl(0, 100%, 40%);">-                              break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_var_delete(n);</span><br><span style="color: hsl(0, 100%, 40%);">-      ast_free(rule_head);</span><br><span style="color: hsl(0, 100%, 40%);">-    return ret;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_full(struct ast_channel *chan, const char *string,</span><br><span style="color: hsl(0, 100%, 40%);">-   const char *ints, const char *lang, const char *options,</span><br><span style="color: hsl(0, 100%, 40%);">-        int audiofd, int ctrlfd)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       say_args_t a = { chan, ints, lang, audiofd, ctrlfd };</span><br><span style="color: hsl(0, 100%, 40%);">-   return do_say(&a, string, options, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_number_full(struct ast_channel *chan, int num,</span><br><span style="color: hsl(0, 100%, 40%);">-        const char *ints, const char *lang, const char *options,</span><br><span style="color: hsl(0, 100%, 40%);">-        int audiofd, int ctrlfd)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       char buf[64];</span><br><span style="color: hsl(0, 100%, 40%);">-   say_args_t a = { chan, ints, lang, audiofd, ctrlfd };</span><br><span style="color: hsl(0, 100%, 40%);">-   snprintf(buf, sizeof(buf), "num:%d", num);</span><br><span style="color: hsl(0, 100%, 40%);">-    return do_say(&a, buf, options, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_enumeration_full(struct ast_channel *chan, int num,</span><br><span style="color: hsl(0, 100%, 40%);">-      const char *ints, const char *lang, const char *options,</span><br><span style="color: hsl(0, 100%, 40%);">-        int audiofd, int ctrlfd)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-       char buf[64];</span><br><span style="color: hsl(0, 100%, 40%);">-   say_args_t a = { chan, ints, lang, audiofd, ctrlfd };</span><br><span style="color: hsl(0, 100%, 40%);">-   snprintf(buf, sizeof(buf), "enum:%d", num);</span><br><span style="color: hsl(0, 100%, 40%);">-   return do_say(&a, buf, options, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_date_generic(struct ast_channel *chan, time_t t,</span><br><span style="color: hsl(0, 100%, 40%);">- const char *ints, const char *lang, const char *format, const char *timezonename, const char *prefix)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  char buf[128];</span><br><span style="color: hsl(0, 100%, 40%);">-  struct ast_tm tm;</span><br><span style="color: hsl(0, 100%, 40%);">-       struct timeval when = { t, 0 };</span><br><span style="color: hsl(0, 100%, 40%);">- say_args_t a = { chan, ints, lang, -1, -1 };</span><br><span style="color: hsl(0, 100%, 40%);">-    if (format == NULL)</span><br><span style="color: hsl(0, 100%, 40%);">-             format = "";</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  ast_localtime(&when, &tm, timezonename);</span><br><span style="color: hsl(0, 100%, 40%);">-        snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",</span><br><span style="color: hsl(0, 100%, 40%);">-          prefix,</span><br><span style="color: hsl(0, 100%, 40%);">-         format,</span><br><span style="color: hsl(0, 100%, 40%);">-         tm.tm_year+1900,</span><br><span style="color: hsl(0, 100%, 40%);">-                tm.tm_mon+1,</span><br><span style="color: hsl(0, 100%, 40%);">-            tm.tm_mday,</span><br><span style="color: hsl(0, 100%, 40%);">-             tm.tm_hour,</span><br><span style="color: hsl(0, 100%, 40%);">-             tm.tm_min,</span><br><span style="color: hsl(0, 100%, 40%);">-              tm.tm_sec,</span><br><span style="color: hsl(0, 100%, 40%);">-              tm.tm_wday,</span><br><span style="color: hsl(0, 100%, 40%);">-             tm.tm_yday);</span><br><span style="color: hsl(0, 100%, 40%);">-    return do_say(&a, buf, NULL, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_date_with_format(struct ast_channel *chan, time_t t,</span><br><span style="color: hsl(0, 100%, 40%);">-        const char *ints, const char *lang, const char *format, const char *timezonename)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-      return say_date_generic(chan, t, ints, lang, format, timezonename, "datetime");</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-  return say_date_generic(chan, t, ints, lang, "", NULL, "date");</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_time(struct ast_channel *chan, time_t t, const char *ints, const char *lang)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        return say_date_generic(chan, t, ints, lang, "", NULL, "time");</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_datetime(struct ast_channel *chan, time_t t, const char *ints, const char *lang)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief</span><br><span style="color: hsl(0, 100%, 40%);">- * remap the 'say' functions to use those in this file</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-static int say_init_mode(const char *mode) {</span><br><span style="color: hsl(0, 100%, 40%);">- if (!strcmp(mode, say_new)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           if (say_cfg == NULL) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  ast_log(LOG_ERROR, "There is no say.conf file to use new mode\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                    return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               save_say_mode(say_new);</span><br><span style="color: hsl(0, 100%, 40%);">-         ast_say_number_full = say_number_full;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_say_enumeration_full = say_enumeration_full;</span><br><span style="color: hsl(0, 100%, 40%);">-#if 0</span><br><span style="color: hsl(0, 100%, 40%);">-           /*! \todo XXX</span><br><span style="color: hsl(0, 100%, 40%);">-              These functions doesn't exist.</span><br><span style="color: hsl(0, 100%, 40%);">-              say.conf.sample indicates this is working...</span><br><span style="color: hsl(0, 100%, 40%);">-         */</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_say_digits_full = say_digits_full;</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_say_digit_str_full = say_digit_str_full;</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_say_character_str_full = say_character_str_full;</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_say_phonetic_str_full = say_phonetic_str_full;</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_say_datetime_from_now = say_datetime_from_now;</span><br><span style="color: hsl(0, 100%, 40%);">-#endif</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_say_datetime = say_datetime;</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_say_time = say_time;</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_say_date = say_date;</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_say_date_with_format = say_date_with_format;</span><br><span style="color: hsl(0, 100%, 40%);">-        } else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {</span><br><span style="color: hsl(0, 100%, 40%);">-               restore_say_mode(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (strcmp(mode, say_old)) {</span><br><span style="color: hsl(0, 100%, 40%);">-             ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);</span><br><span style="color: hsl(0, 100%, 40%);">-         return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static char *__say_cli_init(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-        const char *old_mode = say_api_buf[0] ? say_new : say_old;</span><br><span style="color: hsl(0, 100%, 40%);">-      const char *mode;</span><br><span style="color: hsl(0, 100%, 40%);">-       switch (cmd) {</span><br><span style="color: hsl(0, 100%, 40%);">-  case CLI_INIT:</span><br><span style="color: hsl(0, 100%, 40%);">-          e->command = "say load [new|old]";</span><br><span style="color: hsl(0, 100%, 40%);">-         e->usage =</span><br><span style="color: hsl(0, 100%, 40%);">-                   "Usage: say load [new|old]\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                 "       say load\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                   "           Report status of current say mode\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                      "       say load new\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                       "           Set say method, configured in say.conf\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                 "       say load old\n"</span><br><span style="color: hsl(0, 100%, 40%);">-                       "           Set old say method, coded in asterisk core\n";</span><br><span style="color: hsl(0, 100%, 40%);">-            return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    case CLI_GENERATE:</span><br><span style="color: hsl(0, 100%, 40%);">-              return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (a->argc == 2) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_cli(a->fd, "say mode is [%s]\n", old_mode);</span><br><span style="color: hsl(0, 100%, 40%);">-            return CLI_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-     } else if (a->argc != e->args)</span><br><span style="color: hsl(0, 100%, 40%);">-            return CLI_SHOWUSAGE;</span><br><span style="color: hsl(0, 100%, 40%);">-   mode = a->argv[2];</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!strcmp(mode, old_mode))</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_cli(a->fd, "say mode is %s already\n", mode);</span><br><span style="color: hsl(0, 100%, 40%);">-  else</span><br><span style="color: hsl(0, 100%, 40%);">-            if (say_init_mode(mode) == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_cli(a->fd, "setting say mode from %s to %s\n", old_mode, mode);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        return CLI_SUCCESS;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_cli_entry cli_playback[] = {</span><br><span style="color: hsl(0, 100%, 40%);">-      AST_CLI_DEFINE(__say_cli_init, "Set or show the say mode"),</span><br><span style="color: hsl(0, 100%, 40%);">-};</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static int playback_exec(struct ast_channel *chan, const char *data)</span><br><span> {</span><br><span>         int res = 0;</span><br><span>         int mres = 0;</span><br><span>        char *tmp;</span><br><span>   int option_skip=0;</span><br><span style="color: hsl(0, 100%, 40%);">-      int option_say=0;</span><br><span>    int option_noanswer = 0;</span><br><span> </span><br><span>         AST_DECLARE_APP_ARGS(args,</span><br><span>@@ -464,8 +112,6 @@</span><br><span>     if (args.options) {</span><br><span>          if (strcasestr(args.options, "skip"))</span><br><span>                      option_skip = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-                if (strcasestr(args.options, "say"))</span><br><span style="color: hsl(0, 100%, 40%);">-                  option_say = 1;</span><br><span>              if (strcasestr(args.options, "noanswer"))</span><br><span>                  option_noanswer = 1;</span><br><span>         }</span><br><span>@@ -484,10 +130,7 @@</span><br><span> </span><br><span>                 ast_stopstream(chan);</span><br><span>                while (!res && (front = strsep(&back, "&"))) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (option_say)</span><br><span style="color: hsl(0, 100%, 40%);">-                         res = say_full(chan, front, "", ast_channel_language(chan), NULL, -1, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                    else</span><br><span style="color: hsl(0, 100%, 40%);">-                            res = ast_streamfile(chan, front, ast_channel_language(chan));</span><br><span style="color: hsl(120, 100%, 40%);">+                        res = ast_streamfile(chan, front, ast_channel_language(chan));</span><br><span>                       if (!res) {</span><br><span>                          res = ast_waitstream(chan, "");</span><br><span>                            ast_stopstream(chan);</span><br><span>@@ -506,71 +149,13 @@</span><br><span>        return res;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int reload(void)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">-    struct ast_variable *v;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_flags config_flags = { CONFIG_FLAG_FILEUNCHANGED };</span><br><span style="color: hsl(0, 100%, 40%);">-  struct ast_config *newcfg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if ((newcfg = ast_config_load("say.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {</span><br><span style="color: hsl(0, 100%, 40%);">-            return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       } else if (newcfg == CONFIG_STATUS_FILEINVALID) {</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_log(LOG_ERROR, "Config file say.conf is in an invalid format.  Aborting.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-             return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (say_cfg) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_config_destroy(say_cfg);</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_log(LOG_NOTICE, "Reloading say.conf\n");</span><br><span style="color: hsl(0, 100%, 40%);">-  }</span><br><span style="color: hsl(0, 100%, 40%);">-       say_cfg = newcfg;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (say_cfg) {</span><br><span style="color: hsl(0, 100%, 40%);">-          for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (ast_extension_match(v->name, "mode")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                say_init_mode(v->value);</span><br><span style="color: hsl(0, 100%, 40%);">-                             break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /*! \todo</span><br><span style="color: hsl(0, 100%, 40%);">-        * XXX here we should sort rules according to the same order</span><br><span style="color: hsl(0, 100%, 40%);">-     * we have in pbx.c so we have the same matching behaviour.</span><br><span style="color: hsl(0, 100%, 40%);">-      */</span><br><span style="color: hsl(0, 100%, 40%);">-     return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static int unload_module(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       int res;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-        res = ast_unregister_application(app);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  ast_cli_unregister_multiple(cli_playback, ARRAY_LEN(cli_playback));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (say_cfg)</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_config_destroy(say_cfg);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    return res;</span><br><span style="color: hsl(120, 100%, 40%);">+   return ast_unregister_application(app);</span><br><span> }</span><br><span> </span><br><span> static int load_module(void)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   struct ast_variable *v;</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_flags config_flags = { 0 };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-  say_cfg = ast_config_load("say.conf", config_flags);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (say_cfg && say_cfg != CONFIG_STATUS_FILEINVALID) {</span><br><span style="color: hsl(0, 100%, 40%);">-          for (v = ast_variable_browse(say_cfg, "general"); v ; v = v->next) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       if (ast_extension_match(v->name, "mode")) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                say_init_mode(v->value);</span><br><span style="color: hsl(0, 100%, 40%);">-                             break;</span><br><span style="color: hsl(0, 100%, 40%);">-                  }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       ast_cli_register_multiple(cli_playback, ARRAY_LEN(cli_playback));</span><br><span>    return ast_register_application_xml(app, playback_exec);</span><br><span> }</span><br><span> </span><br><span>@@ -578,5 +163,4 @@</span><br><span>      .support_level = AST_MODULE_SUPPORT_CORE,</span><br><span>    .load = load_module,</span><br><span>         .unload = unload_module,</span><br><span style="color: hsl(0, 100%, 40%);">-        .reload = reload,</span><br><span> );</span><br><span>diff --git a/configs/samples/say.conf.sample b/configs/samples/say.conf.sample</span><br><span>deleted file mode 100644</span><br><span>index de35ee4..0000000</span><br><span>--- a/configs/samples/say.conf.sample</span><br><span>+++ /dev/null</span><br><span>@@ -1,383 +0,0 @@</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; language configuration</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[general]</span><br><span style="color: hsl(0, 100%, 40%);">-mode=old     ; method for playing numbers and dates</span><br><span style="color: hsl(0, 100%, 40%);">-          ; old - using asterisk core function</span><br><span style="color: hsl(0, 100%, 40%);">-            ; new - using this configuration file</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-; The new language routines produce strings of the form</span><br><span style="color: hsl(0, 100%, 40%);">-;   prefix:[format:]data</span><br><span style="color: hsl(0, 100%, 40%);">-; that are matched against the rules in this file to produce</span><br><span style="color: hsl(0, 100%, 40%);">-; an output.</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; The data is generally the string to be spelled (either a number,</span><br><span style="color: hsl(0, 100%, 40%);">-; an ascii string or a date/time in the format specified below).</span><br><span style="color: hsl(0, 100%, 40%);">-; It is available, in the right hand side of a rule, as variable ${SAY}.</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; The format is optional and normally used only for date/time.</span><br><span style="color: hsl(0, 100%, 40%);">-; The prefix is used to select the pronunciation - standard</span><br><span style="color: hsl(0, 100%, 40%);">-; prefixes are</span><br><span style="color: hsl(0, 100%, 40%);">-;        num             used for numbers</span><br><span style="color: hsl(0, 100%, 40%);">-;       enum            used for enumerations</span><br><span style="color: hsl(0, 100%, 40%);">-;  date            for dates</span><br><span style="color: hsl(0, 100%, 40%);">-;      time            for times</span><br><span style="color: hsl(0, 100%, 40%);">-;      datetime        for dates and times</span><br><span style="color: hsl(0, 100%, 40%);">-;    char            for character strings</span><br><span style="color: hsl(0, 100%, 40%);">-;  phonetic        for phonetic strings</span><br><span style="color: hsl(0, 100%, 40%);">-;   digit           for digit strings</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; but others can be used at will.</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; Processing occurs as follows:</span><br><span style="color: hsl(0, 100%, 40%);">-; If the format is empty, or there is no format, the entire</span><br><span style="color: hsl(0, 100%, 40%);">-; string is matched against one of the pattern on the left hand side.</span><br><span style="color: hsl(0, 100%, 40%);">-; On the first match, the various comma-separated components on the right</span><br><span style="color: hsl(0, 100%, 40%);">-; hand side are pronounced, as follows:</span><br><span style="color: hsl(0, 100%, 40%);">-; + a component starting with a prefix: (i.e. with a ':' in it)</span><br><span style="color: hsl(0, 100%, 40%);">-;   is re-processed according to these rules;</span><br><span style="color: hsl(0, 100%, 40%);">-; + a component without a ':' in it is considered a filename and</span><br><span style="color: hsl(0, 100%, 40%);">-;   the corresponding file is played.</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; If the format is non-empty, the format is split into its components</span><br><span style="color: hsl(0, 100%, 40%);">-; (individual characters, or filenames in single quotes), and then</span><br><span style="color: hsl(0, 100%, 40%);">-; filenames are played, whereas single characters are used to</span><br><span style="color: hsl(0, 100%, 40%);">-; generate a new string format:pat:data to be processed.</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; DATES/AND TIMES assume that the date info is available in</span><br><span style="color: hsl(0, 100%, 40%);">-; the form  YYYYMMDDHHmm.ss-dow-doy</span><br><span style="color: hsl(0, 100%, 40%);">-; with 4 digits for the year, 2 for month, day, hour, minutes, seconds,</span><br><span style="color: hsl(0, 100%, 40%);">-; one digit for the day-of-week, and 3 digits for the day-of-year.</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; Example:</span><br><span style="color: hsl(0, 100%, 40%);">-;     datetime::200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-; (typical format for a date) is first matched against the line</span><br><span style="color: hsl(0, 100%, 40%);">-;       datetime::. => date:AdBY 'digits/at' IMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-; which is normally present with the default format for dates.</span><br><span style="color: hsl(0, 100%, 40%);">-; In turn, the format string "AdBY 'digits/at' IMp" results in</span><br><span style="color: hsl(0, 100%, 40%);">-; the sequence</span><br><span style="color: hsl(0, 100%, 40%);">-; date:A:200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-;   date:d:200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-;   date:B:200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-;   date:Y:200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-;   digits/at</span><br><span style="color: hsl(0, 100%, 40%);">-;      date:I:200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-;   date:M:200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-;   date:p:200604172030.00-4-102</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-;</span><br><span style="color: hsl(0, 100%, 40%);">-; Remember, normally X Z N are special, and the search is</span><br><span style="color: hsl(0, 100%, 40%);">-; case insensitive, so you must use [X] [N] [Z] .. if you</span><br><span style="color: hsl(0, 100%, 40%);">-; want exact match.</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-; We start with the basic rules that might be more-or-less</span><br><span style="color: hsl(0, 100%, 40%);">-; language-independent</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[digit-base](!)              ; base rule for digit strings</span><br><span style="color: hsl(0, 100%, 40%);">-                   ; XXX incomplete yet</span><br><span style="color: hsl(0, 100%, 40%);">-    _digit:[0-9] => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _digit:[-] => letters/dash</span><br><span style="color: hsl(0, 100%, 40%);">-    _digit:[*] => letters/star</span><br><span style="color: hsl(0, 100%, 40%);">-    _digit:[@] => letters/at</span><br><span style="color: hsl(0, 100%, 40%);">-    _digit:[0-9]. => digit:${SAY:0:1}, digit:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[date-base](!)         ; base rules for dates and times</span><br><span style="color: hsl(0, 100%, 40%);">-    ; the 'SAY' variable contains YYYYMMDDHHmm.ss-dow-doy</span><br><span style="color: hsl(0, 100%, 40%);">-    ; these rule map the strftime attributes.</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:Y:. => num:${SAY:0:4}        ; year, 19xx</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[Bbh]:. => digits/mon-$[${SAY:4:2}-1]                  ; month name, 0..11</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[Aa]:. => digits/day-${SAY:16:1}        ; day of week</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[de]:. => num:${SAY:6:2}              ; day of month</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[H]:. => digits/oh, num:${SAY:8:2}                   ; hour (oh one, oh two, ..., oh nine, ten, eleven, ..., twenty-three)</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[I]:. => num:$[${SAY:8:2} % 12]       ; hour 0-12</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[M]:. => num:${SAY:10:2}                ; minute</span><br><span style="color: hsl(0, 100%, 40%);">-    ; XXX too bad the '?' function does not remove the quotes</span><br><span style="color: hsl(0, 100%, 40%);">-    ; _date:[pP]:. => digits/$[ ${SAY:10:2} > 12 ? "p-m" :: "a-m"]       ; am pm</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[pP]:. => digits/p-m        ; am pm</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[S]:. => num:${SAY:13:2}            ; seconds</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[Ii]:. => num:$[${SAY:8:2} % 12]                  ; hour 0-12</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[k]:. => num:${SAY:8:2}                         ; hour (one, two. three, ...,twenty three</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[m]:. => num:${SAY:4:2}                           ; month number</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[Q]:. => date:dby ;incompleat                                ; "today", "yesterday" or ABdY</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[q]:. => date:dby ;incompleat                            ; "" (for today), "yesterday", weekday, or ABdY</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[R]:. => date:HM${SAY}                          ; 24 hour time, including minute</span><br><span style="color: hsl(0, 100%, 40%);">-    _date:[T]:. => date:HMS${SAY}                            ; 24 hour, minure, seconds</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[en-base](!)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:0. => num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]0 =>  digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9][1-9] =>  digits/${SAY:0:1}0, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X00 => num:${SAY:0:1}, digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000 => num:${SAY:0:1}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000 => num:${SAY:0:2}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000000 => num:${SAY:0:1}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000 => num:${SAY:0:2}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000 => num:${SAY:0:3}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000000000 => num:${SAY:0:1}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    ; enumeration</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:X => digits/h-${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:1X => digits/h-${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[2-9]0 => digits/h-${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[2-9][1-9] => num:${SAY:0:1}0, digits/h-${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[1-9]00 => num:${SAY:0:1}, digits/h-hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[1-9]XX => num:${SAY:0:1}, digits/h-hundred, enum:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[en_GB](date-base,digit-base,en-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX => num:${SAY:0:1}, digits/hundred, vm-and, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[it](digit-base,date-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:0. => num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]0 =>  digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9][1-9] =>  digits/${SAY:0:1}0, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:100 => digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XX => digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]00 => num:${SAY:0:1}, digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000 => digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXX => digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000 => num:${SAY:0:1}, digits/thousands</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXX => num:${SAY:0:1}, digits/thousands, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000 => num:${SAY:0:2}, digits/thousands</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXX => num:${SAY:0:2}, digits/thousands, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000 => num:${SAY:0:3}, digits/thousands</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousands, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000000 => num:${SAY:0:1}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000000 => num:${SAY:0:1}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXXXXX => num:${SAY:0:1}, digits/millions, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000 => num:${SAY:0:2}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000000000 => num:${SAY:0:1}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _datetime::. => date:AdBY 'digits/at' IMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _date::. => date:AdBY:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _time::. => date:IMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[en](en-base,date-base,digit-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _datetime::. => date:AdBY 'digits/at' IMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _date::. => date:AdBY:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _time::. => date:IMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[de](date-base,digit-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:0. => num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]0 => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9][1-9] => digits/${SAY:1}-and, digits/${SAY:0:1}0</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:100 => digits/ein, digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XX => digits/ein, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]00 => digits/${SAY:0:1}, digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000 => digits/ein, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXX => digits/ein, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000 => digits/${SAY:0:1}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXX => digits/${SAY:0:1}, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000 => num:${SAY:0:2}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000000 => digits/eine, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXXXXX => digits/eine, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000000 => digits/${SAY:0:1}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXXXXX => digits/${SAY:0:1}, digits/millions, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000 => num:${SAY:0:2}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _datetime::. => date:AdBY 'digits/at' IMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _date::. => date:AdBY:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _time::. => date:IMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[hu](digit-base,date-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:0. => num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1[1-9] => digits/10en, digits/${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:2[1-9] => digits/20on, digits/${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[1-9]0 =>  digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[3-9][1-9] =>  digits/${SAY:0:1}0, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000 => num:${SAY:0:1}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000 => num:${SAY:0:2}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000000 => num:${SAY:0:1}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000 => num:${SAY:0:2}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000 => num:${SAY:0:3}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000000000 => num:${SAY:0:1}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _datetime::. => date:YBdA k 'ora' M 'perc':${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _date::. => date:YBdA:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _time::. => date:k 'ora' M 'perc':${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[fr](date-base,digit-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:0. => num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]0 =>  digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-6]1 => digits/${SAY:0:1}0, vm-and, digits/${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:71 => digits/60, vm-and, num:1${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:7X => digits/60, num:1${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:9X => digits/80, num:1${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9][1-9] =>  digits/${SAY:0:1}0, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:100 => digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XX => digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]00 => num:${SAY:0:1}, digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XX => num:${SAY:0:1}, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000 => digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXX => digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000 => num:${SAY:0:1}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000 => num:${SAY:0:2}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000000 => num:${SAY:0:1}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000000 => num:${SAY:0:1}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXXXXX => num:${SAY:0:1}, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000 => num:${SAY:0:2}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/million, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000 => num:${SAY:0:3}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/million, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _datetime::. => date:AdBY 'digits/at' H 'hours' M 'perc':${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _date::. => date:AdBY:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _time::. => date:H 'hours' M 'perc':${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _pho[n]e:XXXX => num:${SAY:0:2}, num:${SAY:2:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _pho[n]e:0[1-9]XXXXXXXX => num:${SAY:0:1}, num:${SAY:1:1}, num:${SAY:2:2}, num:${SAY:4:2}, num:${SAY:6:2}, num:${SAY:8:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _pho[n]e:. => digit:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[es](date-base,digit-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:0. => num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]0 => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:2[1-9] => digits/20-and, digits/${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[3-9][1-9] =>  digits/${SAY:0:1}0, vm-and, digits/${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:100 => digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XX => digits/100-and, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]00 => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XX => digits/${SAY:0:1}00, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000 => digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXX => digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000 => num:${SAY:0:1}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXX => num:${SAY:0:1}, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000 => num:${SAY:0:2}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000000 => digits/1M, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXXXXX => digits/1M, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000000 => num:${SAY:0:1}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXXXXX => num:${SAY:0:1}, digits/millions, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000 => num:${SAY:0:2}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXX000000 => num:${SAY:0:4}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXX => num:${SAY:0:4}, digits/millions, num:${SAY:4}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _datetime::. => date:Ad 'letters/d' B 'letters/d' Y 'digits/at' HMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _date::. => date:Ad 'letters/d' B 'letters/d' Y:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _time::. => date:HMp:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-[da](date-base,digit-base)</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:0. => num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1X => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]0 => digits/${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9][1-9] => digits/${SAY:1}-and, digits/${SAY:0:1}0</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:100 => digits/1N, digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XX => digits/1N, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]00 => digits/${SAY:0:1}, digits/hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XX => digits/${SAY:0:1}, digits/hundred, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1000 => digits/1N, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:1XXX => digits/1N, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]000 => digits/${SAY:0:1}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:[2-9]XXX => digits/${SAY:0:1}, digits/thousand, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000 => num:${SAY:0:2}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXX => num:${SAY:0:2}, digits/thousand, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000 => num:${SAY:0:3}, digits/thousand</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXX => num:${SAY:0:3}, digits/thousand, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000000 => digits/${SAY:0:1}, digits/million</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXX => digits/${SAY:0:1}, digits/million, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000 => num:${SAY:0:2}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXX => num:${SAY:0:2}, digits/millions, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000 => num:${SAY:0:3}, digits/millions</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXX => num:${SAY:0:3}, digits/millions, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:X000000000 => num:${SAY:0:1}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXX => num:${SAY:0:1}, digits/billion, num:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XX000000000 => num:${SAY:0:2}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXX => num:${SAY:0:2}, digits/billion, num:${SAY:2}</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXX000000000 => num:${SAY:0:3}, digits/billion</span><br><span style="color: hsl(0, 100%, 40%);">-    _[n]um:XXXXXXXXXXXX => num:${SAY:0:3}, digits/billion, num:${SAY:3}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    _datetime::. => date:AdBY 'digits/at' kM:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _date::. => date:AdBY:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _time::. => date:HM:${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    ; enumeration</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:X => digits/h-${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:1X => digits/h-${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[2-9]0 => digits/h-${SAY}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[2-9][1-9] => digits/${SAY:1}-and, digits/h-${SAY:0:1}0</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:100 => digits/1N, digits/h-hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:1XX => digits/1N, digits/h-hundred, enum:${SAY:1}</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[2-9]00 => num:${SAY:0:1}, digits/h-hundred</span><br><span style="color: hsl(0, 100%, 40%);">-    _e[n]um:[2-9]XX => num:${SAY:0:1}, digits/h-hundred, enum:${SAY:1}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16623">change 16623</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/16623"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I3200aa184d97679e4a134ec1de82389203d2a0de </div>
<div style="display:none"> Gerrit-Change-Number: 16623 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Sean Bright <sean@seanbright.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>