commit 38f429a3d26122af61b73a8965b1e8e9043c0a0c
Author: Silvan Jegen <[email protected]>
Date:   Fri Nov 15 17:25:10 2013 +0100

    Add the tr program including man page

diff --git a/Makefile b/Makefile
index 81dfaf6..ee84221 100644
--- a/Makefile
+++ b/Makefile
@@ -81,6 +81,7 @@ SRC = \
        tee.c      \
        test.c     \
        touch.c    \
+       tr.c       \
        true.c     \
        tty.c      \
        uname.c    \
diff --git a/tr.1 b/tr.1
new file mode 100644
index 0000000..662b4f8
--- /dev/null
+++ b/tr.1
@@ -0,0 +1,50 @@
+.TH TR 1 sbase\-VERSION
+.SH NAME
+tr \- translate characters
+.SH SYNOPSIS
+.B tr
+.RB set1
+.RI [ set2 ]
+.SH DESCRIPTION
+.B tr
+reads input from stdin replacing every character in
+.B set1
+with the character at the same index in
+.B set2.
+If set2 is not given
+.B tr
+deletes the characters in set1 from the input.
+
+Sets are specified as strings of characters. Almost all represent themselves. 
The following ones will be interpreted:
+.TP
+\e\e
+backslash
+.TP
+\ea
+audible BEL
+.TP
+\ef
+form feed
+.TP
+\en
+new line
+.TP
+\er
+return
+.TP
+\et
+horizontal tab
+.TP
+\ev
+vertical tab
+.PP
+If set1 is longer than set2
+.B tr
+will map all the remaining characters to the last one in set2. In case set2 is 
longer than set1, the remaining characters from set2 will be ignored.
+.B
+.SH NOTES
+.B tr
+is Unicode-aware but does not yet handle character classes (e.g. [:alnum:] or 
[:digit:]).
+.SH SEE ALSO
+.IR sed(1)
+.IR awk(1)
diff --git a/tr.c b/tr.c
new file mode 100644
index 0000000..8cca430
--- /dev/null
+++ b/tr.c
@@ -0,0 +1,151 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <locale.h>
+#include <wchar.h>
+#include "text.h"
+#include "util.h"
+
+static void
+usage(void)
+{
+       eprintf("usage: %s set1 [set2]
", argv0);
+}
+
+void
+handleescapes(char *s)
+{
+       switch(*s) {
+       case 'n':
+               *s = '
';
+               break;
+       case 't':
+               *s = '  ';
+               break;
+       case '\':
+               *s = '\';
+               break;
+       case 'r':
+               *s = '
';
+               break;
+       case 'f':
+               *s = '';
+               break;
+       case 'a':
+               *s = '';
+               break;
+       case 'b':
+               *s = '';
+               break;
+       case 'v':
+               *s = '';
+               break;
+       }
+}
+
+void
+parsemapping(const char *set1, const char *set2, wchar_t *mappings)
+{
+       char *s;
+       wchar_t runeleft;
+       wchar_t runeright;
+       int leftbytes;
+       int rightbytes;
+       size_t n = 0;
+       size_t lset2;
+
+       if(set2) {
+               lset2 = strnlen(set2, 255 * sizeof(wchar_t));
+       } else {
+               set2 = &set1[0];
+               lset2 = 0;
+       }
+
+       s = (char *)set1;
+       while(*s) {
+               if(*s == '\')
+                       handleescapes(++s);
+               leftbytes = mbtowc(&runeleft, s, 4);
+               if(set2[n] != '

Reply via email to