]> diplodocus.org Git - nmh/commitdiff
add "%(units)" function, to express numbers with SI units
authorPaul Fox <pgf@foxharp.boston.ma.us>
Tue, 6 May 2014 21:28:18 +0000 (17:28 -0400)
committerPaul Fox <pgf@foxharp.boston.ma.us>
Wed, 7 May 2014 15:29:29 +0000 (11:29 -0400)
i.e., 1510 --> 1.5K, 15780000 --> 15.8M  etc.  useful with %(size),
as in %(units(size)).

h/fmt_compile.h
man/mh-format.man
sbr/fmt_compile.c
sbr/fmt_scan.c
uip/fmtdump.c

index 84f7fa4..08eb8d6 100644 (file)
 #define FT_LS_WEEKDAY  35      /* set "str" to long tws weekday            */
 #define FT_LS_822DATE  36      /* set "str" to 822 date str                */
 #define FT_LS_PRETTY   37      /* set "str" to pretty (?) date str         */
 #define FT_LS_WEEKDAY  35      /* set "str" to long tws weekday            */
 #define FT_LS_822DATE  36      /* set "str" to 822 date str                */
 #define FT_LS_PRETTY   37      /* set "str" to pretty (?) date str         */
-#define FT_LV_SEC      38      /* set "value" to tws second                */
-#define FT_LV_MIN      39      /* set "value" to tws minute                */
-#define FT_LV_HOUR     40      /* set "value" to tws hour                  */
-#define FT_LV_MDAY     41      /* set "value" to tws day of month          */
-#define FT_LV_MON      42      /* set "value" to tws month                 */
-#define FT_LV_YEAR     43      /* set "value" to tws year                  */
-#define FT_LV_YDAY     44      /* set "value" to tws day of year           */
-#define FT_LV_WDAY     45      /* set "value" to tws weekday               */
-#define FT_LV_ZONE     46      /* set "value" to tws timezone              */
-#define FT_LV_CLOCK    47      /* set "value" to tws clock                 */
-#define FT_LV_RCLOCK   48      /* set "value" to now - tws clock           */
-#define FT_LV_DAYF     49      /* set "value" to tws day flag              */
-#define FT_LV_DST      50      /* set "value" to tws daylight savings flag */
-#define FT_LV_ZONEF    51      /* set "value" to tws timezone flag         */
+#define FT_LS_UNITS    38      /* set "str" to "<value>[KMGT]"             */
+#define FT_LV_SEC      39      /* set "value" to tws second                */
+#define FT_LV_MIN      40      /* set "value" to tws minute                */
+#define FT_LV_HOUR     41      /* set "value" to tws hour                  */
+#define FT_LV_MDAY     42      /* set "value" to tws day of month          */
+#define FT_LV_MON      43      /* set "value" to tws month                 */
+#define FT_LV_YEAR     44      /* set "value" to tws year                  */
+#define FT_LV_YDAY     45      /* set "value" to tws day of year           */
+#define FT_LV_WDAY     46      /* set "value" to tws weekday               */
+#define FT_LV_ZONE     47      /* set "value" to tws timezone              */
+#define FT_LV_CLOCK    48      /* set "value" to tws clock                 */
+#define FT_LV_RCLOCK   49      /* set "value" to now - tws clock           */
+#define FT_LV_DAYF     50      /* set "value" to tws day flag              */
+#define FT_LV_DST      51      /* set "value" to tws daylight savings flag */
+#define FT_LV_ZONEF    52      /* set "value" to tws timezone flag         */
 
 
-#define FT_LS_PERS     52      /* set "str" to person part of addr    */
-#define FT_LS_MBOX     53      /* set "str" to mbox part of addr      */
-#define FT_LS_HOST     54      /* set "str" to host part of addr      */
-#define FT_LS_PATH     55      /* set "str" to route part of addr     */
-#define FT_LS_GNAME    56      /* set "str" to group part of addr     */
-#define FT_LS_NOTE     57      /* set "str" to comment part of addr   */
-#define FT_LS_ADDR     58      /* set "str" to mbox@host              */
-#define FT_LS_822ADDR  59      /* set "str" to 822 format addr        */
-#define FT_LS_FRIENDLY 60      /* set "str" to "friendly" format addr */
-#define FT_LV_HOSTTYPE 61      /* set "value" to addr host type       */
-#define FT_LV_INGRPF   62      /* set "value" to addr in-group flag   */
-#define FT_LS_UNQUOTE  63      /* remove RFC 2822 quotes from "str"   */
-#define FT_LV_NOHOSTF  64      /* set "value" to addr no-host flag */
+#define FT_LS_PERS     53      /* set "str" to person part of addr    */
+#define FT_LS_MBOX     54      /* set "str" to mbox part of addr      */
+#define FT_LS_HOST     55      /* set "str" to host part of addr      */
+#define FT_LS_PATH     56      /* set "str" to route part of addr     */
+#define FT_LS_GNAME    57      /* set "str" to group part of addr     */
+#define FT_LS_NOTE     58      /* set "str" to comment part of addr   */
+#define FT_LS_ADDR     59      /* set "str" to mbox@host              */
+#define FT_LS_822ADDR  60      /* set "str" to 822 format addr        */
+#define FT_LS_FRIENDLY 61      /* set "str" to "friendly" format addr */
+#define FT_LV_HOSTTYPE 62      /* set "value" to addr host type       */
+#define FT_LV_INGRPF   63      /* set "value" to addr in-group flag   */
+#define FT_LS_UNQUOTE  64      /* remove RFC 2822 quotes from "str"   */
+#define FT_LV_NOHOSTF  65      /* set "value" to addr no-host flag */
 
 /* Date Coercion */
 
 /* Date Coercion */
-#define FT_LOCALDATE   65      /* Coerce date to local timezone */
-#define FT_GMTDATE     66      /* Coerce date to gmt            */
+#define FT_LOCALDATE   66      /* Coerce date to local timezone */
+#define FT_GMTDATE     67      /* Coerce date to gmt            */
 
 /* pre-format processing */
 
 /* pre-format processing */
-#define FT_PARSEDATE   67      /* parse comp into a date (tws) struct */
-#define FT_PARSEADDR   68      /* parse comp into a mailaddr struct   */
-#define FT_FORMATADDR  69      /* let external routine format addr    */
-#define FT_CONCATADDR  70      /* formataddr w/out duplicate removal  */
-#define FT_MYMBOX      71      /* do "mymbox" test on comp            */
+#define FT_PARSEDATE   68      /* parse comp into a date (tws) struct */
+#define FT_PARSEADDR   69      /* parse comp into a mailaddr struct   */
+#define FT_FORMATADDR  70      /* let external routine format addr    */
+#define FT_CONCATADDR  71      /* formataddr w/out duplicate removal  */
+#define FT_MYMBOX      72      /* do "mymbox" test on comp            */
 
 /* conditionals & control flow (must be last) */
 
 /* conditionals & control flow (must be last) */
-#define FT_SAVESTR     72      /* save current str reg               */
-#define FT_DONE                73      /* stop formatting                    */
-#define FT_PAUSE       74      /* pause                              */
-#define FT_NOP         75      /* nop                                */
-#define FT_GOTO                76      /* (relative) goto                    */
-#define FT_IF_S_NULL   77      /* test if "str" null                 */
-#define FT_IF_S                78      /* test if "str" non-null             */
-#define FT_IF_V_EQ     79      /* test if "value" = literal          */
-#define FT_IF_V_NE     80      /* test if "value" != literal         */
-#define FT_IF_V_GT     81      /* test if "value" > literal          */
-#define FT_IF_MATCH    82      /* test if "str" contains literal     */
-#define FT_IF_AMATCH   83      /* test if "str" starts with literal  */
-#define FT_S_NULL      84      /* V = 1 if "str" null                */
-#define FT_S_NONNULL   85      /* V = 1 if "str" non-null            */
-#define FT_V_EQ                86      /* V = 1 if "value" = literal         */
-#define FT_V_NE                87      /* V = 1 if "value" != literal        */
-#define FT_V_GT                88      /* V = 1 if "value" > literal         */
-#define FT_V_MATCH     89      /* V = 1 if "str" contains literal    */
-#define FT_V_AMATCH    90      /* V = 1 if "str" starts with literal */
+#define FT_SAVESTR     73      /* save current str reg               */
+#define FT_DONE                74      /* stop formatting                    */
+#define FT_PAUSE       75      /* pause                              */
+#define FT_NOP         76      /* nop                                */
+#define FT_GOTO                77      /* (relative) goto                    */
+#define FT_IF_S_NULL   78      /* test if "str" null                 */
+#define FT_IF_S                79      /* test if "str" non-null             */
+#define FT_IF_V_EQ     80      /* test if "value" = literal          */
+#define FT_IF_V_NE     81      /* test if "value" != literal         */
+#define FT_IF_V_GT     82      /* test if "value" > literal          */
+#define FT_IF_MATCH    83      /* test if "str" contains literal     */
+#define FT_IF_AMATCH   84      /* test if "str" starts with literal  */
+#define FT_S_NULL      85      /* V = 1 if "str" null                */
+#define FT_S_NONNULL   86      /* V = 1 if "str" non-null            */
+#define FT_V_EQ                87      /* V = 1 if "value" = literal         */
+#define FT_V_NE                88      /* V = 1 if "value" != literal        */
+#define FT_V_GT                89      /* V = 1 if "value" > literal         */
+#define FT_V_MATCH     90      /* V = 1 if "str" contains literal    */
+#define FT_V_AMATCH    91      /* V = 1 if "str" starts with literal */
 
 #define IF_FUNCS FT_S_NULL     /* start of "if" functions */
 
 #define IF_FUNCS FT_S_NULL     /* start of "if" functions */
index 5610a9a..4dfa263 100644 (file)
@@ -290,6 +290,7 @@ decode      expr    string  decode \fIstr\fR as RFC 2047 (MIME-encoded)
                        component
 unquote        expr    string  remove RFC 2822 quotes from \fIstr\fR
 trim   expr            trim trailing whitespace from \fIstr\fR
                        component
 unquote        expr    string  remove RFC 2822 quotes from \fIstr\fR
 trim   expr            trim trailing whitespace from \fIstr\fR
+units  expr    string  convert number to SI units ("15.1K")
 putstr expr            print \fIstr\fR
 putstrf        expr            print \fIstr\fR in a fixed width
 putnum expr            print \fInum\fR
 putstr expr            print \fIstr\fR
 putstrf        expr            print \fIstr\fR in a fixed width
 putnum expr            print \fInum\fR
index 3f170f3..200d738 100644 (file)
@@ -159,6 +159,7 @@ static struct ftable functable[] = {
      { "decodecomp", TF_COMP,  FT_LS_DECODECOMP, 0,            TFL_PUTS },
      { "decode",     TF_EXPR,  FT_LS_DECODE,   0,              TFL_PUTS },
      { "trim",       TF_EXPR,  FT_LS_TRIM,     0,              0 },
      { "decodecomp", TF_COMP,  FT_LS_DECODECOMP, 0,            TFL_PUTS },
      { "decode",     TF_EXPR,  FT_LS_DECODE,   0,              TFL_PUTS },
      { "trim",       TF_EXPR,  FT_LS_TRIM,     0,              0 },
+     { "units",      TF_EXPR,  FT_LS_UNITS,    0,              TFL_PUTS  },
      { "compval",    TF_COMP,  FT_LV_COMP,     0,              TFL_PUTN },
      { "compflag",   TF_COMP,  FT_LV_COMPFLAG, 0,              TFL_PUTN },
      { "num",        TF_NUM,   FT_LV_LIT,      0,              TFL_PUTN },
      { "compval",    TF_COMP,  FT_LV_COMP,     0,              TFL_PUTN },
      { "compflag",   TF_COMP,  FT_LV_COMPFLAG, 0,              TFL_PUTN },
      { "num",        TF_NUM,   FT_LV_LIT,      0,              TFL_PUTN },
index e4d79d5..c8cdece 100644 (file)
@@ -490,6 +490,41 @@ fmt_scan (struct format *format, char *scanl, size_t max, int width, int *dat,
                    cp += n;
            }
            break;
                    cp += n;
            }
            break;
+       case FT_LS_UNITS:
+           {
+               char *unitcp;
+               unsigned int whole, tenths;
+
+               if (value < 1000) {
+                   snprintf(buffer, sizeof(buffer), "%u", value);
+               } else {
+
+                   /* find correct scale for size (Kilo/Mega/Giga/Tera) */
+                   for (unitcp = "KMGT"; value > 999999; value /= 1000) {
+                       if (!*++unitcp)
+                           break;
+                   }
+
+                   if (!*unitcp) {
+                       strcpy(buffer, "huge");
+                   } else {
+                       /* round up to next higer tenth of kilo-/mega-/giga- */
+                       value += 99; value /= 100;
+
+                       /* want one digit after decimal, avoid float */
+                       whole = value / 10;
+                       tenths = value - (whole * 10);
+
+                       if (tenths) {
+                           snprintf(buffer, sizeof(buffer), "%u.%u%c", whole, tenths, *unitcp);
+                       } else {
+                           snprintf(buffer, sizeof(buffer), "%u%c", whole, *unitcp);
+                       }
+                   }
+               }
+               str = buffer;
+           }
+           break;
        case FT_NUMF:
            cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp);
            break;
        case FT_NUMF:
            cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp);
            break;
index f1df6f3..7ee5d37 100644 (file)
@@ -371,6 +371,7 @@ f_typestr(int t)
        case FT_LV_DIVIDE_L: return("LV_DIVIDE_L");
        case FT_LV_MODULO_L: return("LV_MODULO_L");
        case FT_LV_CHAR_LEFT: return("LV_CHAR_LEFT");
        case FT_LV_DIVIDE_L: return("LV_DIVIDE_L");
        case FT_LV_MODULO_L: return("LV_MODULO_L");
        case FT_LV_CHAR_LEFT: return("LV_CHAR_LEFT");
+       case FT_LS_UNITS: return("LS_UNITS");
        case FT_LS_MONTH: return("LS_MONTH");
        case FT_LS_LMONTH: return("LS_LMONTH");
        case FT_LS_ZONE: return("LS_ZONE");
        case FT_LS_MONTH: return("LS_MONTH");
        case FT_LS_LMONTH: return("LS_LMONTH");
        case FT_LS_ZONE: return("LS_ZONE");