tech-userlevel archive

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

Re: humanize_number(3) for dd(1) summary?



On 02.11.2011 15:39, Izumi Tsutsui wrote:
The attached patch extends dd(1) in a way that permits specifying either:
- a msgfmt, with "human", "quiet", "posix" currently in place
- an arbitrary format, when passed as msgfmt=... to command line by user.

It's better to have #ifdef option which disables the new feature
(as current #ifdef NO_CONV via SMALLPROG in Makefile)
for crunched binaries on poor install media.

Done. The option is NO_MSGFMT.

Total binary size:

new dd: 29920
new dd, with SMALLPROG: 24864
old dd: 26677
old dd, with SMALLPROG: 22028

The increase is therefore ~2.5kiB with the modifications when compared with the old binary.

--
Jean-Yves Migeon
jeanyves.migeon%free.fr@localhost
? .gdbinit
? dd
? dd.cat1
? dd.html1
? rump.dd
Index: Makefile
===================================================================
RCS file: /cvsroot/src/bin/dd/Makefile,v
retrieving revision 1.15
diff -u -p -r1.15 Makefile
--- Makefile    4 Feb 2011 19:42:12 -0000       1.15
+++ Makefile    2 Nov 2011 22:21:55 -0000
@@ -8,7 +8,7 @@ DPADD+= ${LIBUTIL}
 LDADD+=        -lutil
 
 .ifdef SMALLPROG
-CPPFLAGS+=     -DNO_CONV -DSMALL
+CPPFLAGS+=     -DNO_CONV -DNO_MSGFMT -DSMALL
 .else
 SRCS+=         conv_tab.c
 .ifndef CRUNCHEDPROG
Index: args.c
===================================================================
RCS file: /cvsroot/src/bin/dd/args.c,v
retrieving revision 1.35
diff -u -p -r1.35 args.c
--- args.c      16 Sep 2011 16:06:23 -0000      1.35
+++ args.c      2 Nov 2011 22:21:55 -0000
@@ -64,11 +64,13 @@ static void f_cbs(char *);
 #ifdef NO_CONV
 __dead
 #endif
+
 static void    f_conv(char *);
 static void    f_count(char *);
 static void    f_files(char *);
 static void    f_ibs(char *);
 static void    f_if(char *);
+static void    f_msgfmt(char *);
 static void    f_obs(char *);
 static void    f_of(char *);
 static void    f_seek(char *);
@@ -90,6 +92,7 @@ static const struct arg {
        { "ibs",        f_ibs,          C_IBS,   C_BS|C_IBS },
        { "if",         f_if,           C_IF,    C_IF },
        { "iseek",      f_skip,         C_SKIP,  C_SKIP },
+       { "msgfmt",     f_msgfmt,       C_SKIP,  C_SKIP },
        { "obs",        f_obs,          C_OBS,   C_BS|C_OBS },
        { "of",         f_of,           C_OF,    C_OF },
        { "oseek",      f_seek,         C_SEEK,  C_SEEK },
@@ -105,6 +108,7 @@ void
 jcl(char **argv)
 {
        struct arg *ap, tmp;
+       //struct dd_msgfmt *fmt;
        char *oper, *arg;
 
        in.dbsz = out.dbsz = 512;
@@ -252,6 +256,24 @@ f_if(char *arg)
        in.name = arg;
 }
 
+#ifdef NO_MSGFMT
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_msgfmt(char *arg)
+{
+
+       errx(EXIT_FAILURE, "msgfmt option disabled");
+       /* NOTREACHED */
+}
+#else  /* NO_MSGFMT */
+static void
+f_msgfmt(char *arg)
+{
+
+       msgfmt = arg;
+}
+#endif /* NO_MSGFMT */
+
 static void
 f_obs(char *arg)
 {
Index: dd.c
===================================================================
RCS file: /cvsroot/src/bin/dd/dd.c,v
retrieving revision 1.47
diff -u -p -r1.47 dd.c
--- dd.c        4 Feb 2011 19:42:12 -0000       1.47
+++ dd.c        2 Nov 2011 22:21:55 -0000
@@ -86,6 +86,7 @@ u_int         files_cnt = 1;          /* # of files to 
 uint64_t       progress = 0;           /* display sign of life */
 const u_char   *ctab;                  /* conversion table */
 sigset_t       infoset;                /* a set blocking SIGINFO */
+const char     *msgfmt = "posix";      /* specifies summary() message format */
 
 /*
  * Ops for stdin/stdout and crunch'd dd.  These are always host ops.
Index: extern.h
===================================================================
RCS file: /cvsroot/src/bin/dd/extern.h,v
retrieving revision 1.20
diff -u -p -r1.20 extern.h
--- extern.h    16 Sep 2011 16:06:23 -0000      1.20
+++ extern.h    2 Nov 2011 22:21:55 -0000
@@ -74,3 +74,4 @@ extern const u_char   a2e_32V[], a2e_POSIX
 extern const u_char    e2a_32V[], e2a_POSIX[];
 extern const u_char    a2ibm_32V[], a2ibm_POSIX[];
 extern u_char          casetab[];
+extern const char      *msgfmt;
Index: misc.c
===================================================================
RCS file: /cvsroot/src/bin/dd/misc.c,v
retrieving revision 1.21
diff -u -p -r1.21 misc.c
--- misc.c      5 Oct 2007 07:23:09 -0000       1.21
+++ misc.c      2 Nov 2011 22:21:55 -0000
@@ -59,50 +59,104 @@ __RCSID("$NetBSD: misc.c,v 1.21 2007/10/
 
 #define        tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
 
+static void posix_summary(void);
+static int  dd_snprintf(char *, size_t, const char *);
+
+#ifndef NO_MSGFMT
+static void custom_summary(void);
+static void human_summary(void);
+static void quiet_summary(void);
+
+static void
+custom_summary(void)
+{
+       char buf[1024];
+
+       dd_snprintf(buf, sizeof(buf), msgfmt);
+
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+static void
+human_summary(void)
+{
+       char buf[100];
+
+       /* Use snprintf(3) so that we don't reenter stdio(3). */
+       (void)dd_snprintf(buf, sizeof(buf),
+           "%I+%i records in\n%O+%o records out\n");
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+       if (st.swab) {
+               (void)dd_snprintf(buf, sizeof(buf), "%w odd length swab %W\n");
+               (void)write(STDERR_FILENO, buf, strlen(buf));
+       }
+       if (st.trunc) {
+               (void)dd_snprintf(buf, sizeof(buf), "%t truncated %T\n");
+               (void)write(STDERR_FILENO, buf, strlen(buf));
+       }
+       if (st.sparse) {
+               (void)dd_snprintf(buf, sizeof(buf), "%p sparse output %P\n");
+               (void)write(STDERR_FILENO, buf, strlen(buf));
+       }
+       (void)dd_snprintf(buf, sizeof(buf),
+           "%b bytes (%B) transferred in %s secs (%e bytes/sec - %E)\n");
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+static void
+quiet_summary(void)
+{
+
+       /* stay quiet */
+}
+#endif /* NO_MSGFMT */
+
 void
 summary(void)
 {
-       char buf[100];
-       int64_t mS;
-       struct timeval tv;
 
        if (progress)
                (void)write(STDERR_FILENO, "\n", 1);
 
-       (void)gettimeofday(&tv, NULL);
-       mS = tv2mS(tv) - tv2mS(st.start);
-       if (mS == 0)
-               mS = 1;
+#ifdef NO_MSGFMT
+       return posix_summary();
+#else /* NO_MSGFMT */
+       if (strncmp(msgfmt, "human", sizeof("human")) == 0)
+               return human_summary();
+
+       if (strncmp(msgfmt, "posix", sizeof("posix")) == 0)
+               return posix_summary();
+
+       if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0)
+               return quiet_summary();
+
+       return custom_summary();
+#endif /* NO_MSGFMT */
+}
+
+static void
+posix_summary(void)
+{
+       char buf[100];
+
        /* Use snprintf(3) so that we don't reenter stdio(3). */
-       (void)snprintf(buf, sizeof(buf),
-           "%llu+%llu records in\n%llu+%llu records out\n",
-           (unsigned long long)st.in_full,  (unsigned long long)st.in_part,
-           (unsigned long long)st.out_full, (unsigned long long)st.out_part);
+       (void)dd_snprintf(buf, sizeof(buf),
+           "%I+%i records in\n%O+%o records out\n");
        (void)write(STDERR_FILENO, buf, strlen(buf));
        if (st.swab) {
-               (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
-                   (unsigned long long)st.swab,
-                   (st.swab == 1) ? "block" : "blocks");
+               (void)dd_snprintf(buf, sizeof(buf), "%w odd length swab %W\n");
                (void)write(STDERR_FILENO, buf, strlen(buf));
        }
        if (st.trunc) {
-               (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
-                   (unsigned long long)st.trunc,
-                   (st.trunc == 1) ? "block" : "blocks");
+               (void)dd_snprintf(buf, sizeof(buf), "%t truncated %T\n");
                (void)write(STDERR_FILENO, buf, strlen(buf));
        }
        if (st.sparse) {
-               (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
-                   (unsigned long long)st.sparse,
-                   (st.sparse == 1) ? "block" : "blocks");
+               (void)dd_snprintf(buf, sizeof(buf), "%p sparse output %P\n");
                (void)write(STDERR_FILENO, buf, strlen(buf));
        }
-       (void)snprintf(buf, sizeof(buf),
-           "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
-           (unsigned long long) st.bytes,
-           (long) (mS / 1000),
-           (int) (mS % 1000),
-           (unsigned long long) (st.bytes * 1000LL / mS));
+       (void)dd_snprintf(buf, sizeof(buf),
+           "%b bytes transferred in %s secs (%e bytes/sec)\n");
        (void)write(STDERR_FILENO, buf, strlen(buf));
 }
 
@@ -123,3 +177,124 @@ terminate(int signo)
        (void)raise_default_signal(signo);
        _exit(127);
 }
+
+static int
+dd_snprintf(char *sbuf, size_t len, const char *fmt)
+{
+       char nbuf[64], hbuf[7];
+       char *ebuf = &sbuf[len - 1], *buf = sbuf;
+       const char *ptr, *s;
+       int64_t mS;
+        struct timeval tv;
+
+       (void)gettimeofday(&tv, NULL);
+       mS = tv2mS(tv) - tv2mS(st.start);
+       if (mS == 0)
+               mS = 1;
+
+#define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \
+       while (/*CONSTCOND*/0)
+#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \
+       while (/*CONSTCOND*/0)
+
+       for (ptr = fmt; *ptr; ptr++) {
+               if (*ptr != '%') {
+                       ADDC(*ptr);
+                       continue;
+               }
+
+               switch (*++ptr) {
+               case 'b':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.bytes);
+                       ADDS(nbuf);
+                       break;
+               case 'B':
+                       if (humanize_number(hbuf, sizeof(hbuf),
+                           st.bytes, "B",
+                           HN_AUTOSCALE, HN_DECIMAL) == -1)
+                               warnx("humanize_number (bytes transferred)");
+                       ADDS(hbuf);
+                       break;
+               case 'e':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long) (st.bytes * 1000LL / mS));
+                       ADDS(nbuf);
+                       break;
+               case 'E':
+                       if (humanize_number(hbuf, sizeof(hbuf),
+                           st.bytes * 1000LL / mS, "B",
+                           HN_AUTOSCALE, HN_DECIMAL) == -1)
+                               warnx("humanize_number (bytes per second)");
+                       ADDS(hbuf); ADDS("/sec");
+                       break;
+               case 'i':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.in_part);
+                       ADDS(nbuf);
+                       break;
+               case 'I':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.in_full);
+                       ADDS(nbuf);
+                       break;
+               case 'o':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.out_part);
+                       ADDS(nbuf);
+                       break;
+               case 'O':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.out_full);
+                       ADDS(nbuf);
+                       break;
+               case 's':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
+                           (long) (mS / 1000), (int) (mS % 1000));
+                       ADDS(nbuf);
+                       break;
+               case 'p':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.sparse);
+                       ADDS(nbuf);
+                       break;
+               case 't':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.trunc);
+                       ADDS(nbuf);
+                       break;
+               case 'w':
+                       (void)snprintf(nbuf, sizeof(nbuf), "%llu",
+                           (unsigned long long)st.swab);
+                       ADDS(nbuf);
+                       break;
+               case 'P':
+                       ADDS("record");
+                       if (st.sparse != 1) ADDS("s");
+                       break;
+               case 'T':
+                       ADDS("record");
+                       if (st.trunc != 1) ADDS("s");
+                       break;
+               case 'W':
+                       ADDS("record");
+                       if (st.swab != 1) ADDS("s");
+                       break;
+               default:
+                       ADDC('%');
+                       if (*ptr == '\0')
+                               goto done;
+                       /*FALLTHROUGH*/
+               case '%':
+                       ADDC(*ptr);
+                       break;
+               }
+       }
+
+done:
+       if (buf < ebuf)
+               *buf = '\0';
+       else if (len != 0)
+               sbuf[len - 1] = '\0';
+       return (int)(buf - sbuf);
+}


Home | Main Index | Thread Index | Old Index