Refactor catv. Move visible() from stty to libbb.
authorBartosz Golaszewski <bartekgola@gmail.com>
Tue, 30 Jul 2013 04:29:42 +0000 (06:29 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 30 Jul 2013 04:29:42 +0000 (06:29 +0200)
Fixes the following TODO:

  stty's visible() function and catv's guts are identical. Merge them into
  an appropriate libbb function.

Also makes catv behave exactly like coreutils' cat -v e.g. it'll print 'M-^I'
instead of 'M-   '.

function                                             old     new   delta
visible                                                -      70     +70
do_display                                           431     379     -52
catv_main                                            306     250     -56
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/2 up/down: 70/-108)           Total: -38 bytes

Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
TODO
coreutils/catv.c
coreutils/stty.c
include/libbb.h
libbb/printable.c

diff --git a/TODO b/TODO
index 8d0850c..d2a085e 100644 (file)
--- a/TODO
+++ b/TODO
@@ -128,10 +128,6 @@ patch
   And while we're at it, a new patch filename quoting format is apparently
   coming soon:  http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
 ---
-stty / catv
-  stty's visible() function and catv's guts are identical. Merge them into
-  an appropriate libbb function.
----
 tail
   ./busybox tail -f foo.c~ TODO
   should not print fmt=header_fmt for subsequent date >> TODO; i.e. only
index 214b431..18b1810 100644 (file)
@@ -25,14 +25,20 @@ int catv_main(int argc UNUSED_PARAM, char **argv)
 {
        int retval = EXIT_SUCCESS;
        int fd;
-       unsigned flags;
+       unsigned opts;
+       int flags = 0;
 
-       flags = getopt32(argv, "etv");
+       opts = getopt32(argv, "etv");
 #define CATV_OPT_e (1<<0)
 #define CATV_OPT_t (1<<1)
 #define CATV_OPT_v (1<<2)
-       flags ^= CATV_OPT_v;
        argv += optind;
+       if (opts & (CATV_OPT_e | CATV_OPT_t))
+               opts &= ~CATV_OPT_v;
+       if (opts & CATV_OPT_e)
+               flags |= VISIBLE_ENDLINE;
+       if (opts & CATV_OPT_t)
+               flags |= VISIBLE_SHOW_TABS;
 
        /* Read from stdin if there's nothing else to do. */
        if (!argv[0])
@@ -50,29 +56,17 @@ int catv_main(int argc UNUSED_PARAM, char **argv)
                        res = read(fd, read_buf, COMMON_BUFSIZE);
                        if (res < 0)
                                retval = EXIT_FAILURE;
-                       if (res < 1)
+                       if (res <= 0)
                                break;
                        for (i = 0; i < res; i++) {
                                unsigned char c = read_buf[i];
-
-                               if (c > 126 && (flags & CATV_OPT_v)) {
-                                       if (c == 127) {
-                                               printf("^?");
-                                               continue;
-                                       }
-                                       printf("M-");
-                                       c -= 128;
-                               }
-                               if (c < 32) {
-                                       if (c == 10) {
-                                               if (flags & CATV_OPT_e)
-                                                       bb_putchar('$');
-                                       } else if (flags & (c==9 ? CATV_OPT_t : CATV_OPT_v)) {
-                                               printf("^%c", c+'@');
-                                               continue;
-                                       }
+                               if (opts & CATV_OPT_v) {
+                                       putchar(c);
+                               } else {
+                                       char buf[sizeof("M-^c")];
+                                       visible(c, buf, flags);
+                                       fputs(buf, stdout);
                                }
-                               bb_putchar(c);
                        }
                }
                if (ENABLE_FEATURE_CLEAN_UP && fd)
index d1e74f4..378a848 100644 (file)
@@ -781,36 +781,6 @@ struct globals {
        G.max_col = 80; \
 } while (0)
 
-
-/* Return a string that is the printable representation of character CH */
-/* Adapted from 'cat' by Torbjorn Granlund */
-static const char *visible(unsigned ch)
-{
-       char *bpout = G.buf;
-
-       if (ch == _POSIX_VDISABLE)
-               return "<undef>";
-
-       if (ch >= 128) {
-               ch -= 128;
-               *bpout++ = 'M';
-               *bpout++ = '-';
-       }
-
-       if (ch < 32) {
-               *bpout++ = '^';
-               *bpout++ = ch + 64;
-       } else if (ch < 127) {
-               *bpout++ = ch;
-       } else {
-               *bpout++ = '^';
-               *bpout++ = '?';
-       }
-
-       *bpout = '\0';
-       return G.buf;
-}
-
 static void set_speed_or_die(enum speed_setting type, const char *arg,
                                        struct termios *mode)
 {
@@ -1038,6 +1008,7 @@ static void do_display(const struct termios *mode, int all)
 #endif
 
        for (i = 0; i != CIDX_min; ++i) {
+               char ch;
                /* If swtch is the same as susp, don't print both */
 #if VSWTCH == VSUSP
                if (i == CIDX_swtch)
@@ -1051,8 +1022,12 @@ static void do_display(const struct termios *mode, int all)
                        continue;
                }
 #endif
-               wrapf("%s = %s;", nth_string(control_name, i),
-                               visible(mode->c_cc[control_info[i].offset]));
+               ch = mode->c_cc[control_info[i].offset];
+               if (ch == _POSIX_VDISABLE)
+                       strcpy(G.buf, "<undef>");
+               else
+                       visible(ch, G.buf, 0);
+               wrapf("%s = %s;", nth_string(control_name, i), G.buf);
        }
 #if VEOF == VMIN
        if ((mode->c_lflag & ICANON) == 0)
index 83e9b5f..0c3734c 100644 (file)
@@ -678,6 +678,10 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str);
  * else it is printed as-is (except for ch = 0x9b) */
 enum { PRINTABLE_META = 0x100 };
 void fputc_printable(int ch, FILE *file) FAST_FUNC;
+/* Return a string that is the printable representation of character ch.
+ * Buffer must hold at least four characters. */
+enum { VISIBLE_SHOW_TABS = 1, VISIBLE_ENDLINE = 2 };
+void visible(unsigned ch, char *buf, int flags) FAST_FUNC;
 
 /* dmalloc will redefine these to it's own implementation. It is safe
  * to have the prototypes here unconditionally.  */
index f6ada49..9a42343 100644 (file)
@@ -32,3 +32,27 @@ void FAST_FUNC fputc_printable(int ch, FILE *file)
        }
        fputc(ch, file);
 }
+
+void FAST_FUNC visible(unsigned ch, char *buf, int flags)
+{
+       if (ch == '\t' && !(flags & VISIBLE_SHOW_TABS)) {
+               goto raw;
+       }
+       if (ch == '\n') {
+               if (flags & VISIBLE_ENDLINE)
+                       *buf++ = '$';
+       } else {
+               if (ch >= 128) {
+                       ch -= 128;
+                       *buf++ = 'M';
+                       *buf++ = '-';
+               }
+               if (ch < 32 || ch == 127) {
+                       *buf++ = '^';
+                       ch ^= 0x40;
+               }
+       }
+ raw:
+       *buf++ = ch;
+       *buf = '\0';
+}