1 /* tr - translate characters Author: Michiel Huisjes */
2 /* Usage: tr [-cds] [string1 [string2]]
3 * c: take complement of string1
4 * d: delete input characters coded string1
5 * s: squeeze multiple output characters of string2 into one character
8 #define BUFFER_SIZE 1024
15 #define NIL_PTR ((char *) 0)
17 BOOL com_fl
, del_fl
, sq_fl
;
19 unsigned char output
[BUFFER_SIZE
], input
[BUFFER_SIZE
];
20 unsigned char vector
[ASCII
+ 1];
21 BOOL invec
[ASCII
+ 1], outvec
[ASCII
+ 1];
23 short in_index
, out_index
;
25 #include <sys/types.h>
30 _PROTOTYPE(int main
, (int argc
, char **argv
));
31 _PROTOTYPE(void convert
, (void));
32 _PROTOTYPE(void map
, (unsigned char *string1
, unsigned char *string2
));
33 _PROTOTYPE(void expand
, (char *arg
, unsigned char *buffer
));
34 _PROTOTYPE(void complement
, (unsigned char *buffer
));
40 register unsigned char *ptr
;
44 if (argc
> 1 && argv
[index
][0] == '-') {
45 for (ptr
= (unsigned char *) &argv
[index
][1]; *ptr
; ptr
++) {
47 case 'c': com_fl
= TRUE
; break;
48 case 'd': del_fl
= TRUE
; break;
49 case 's': sq_fl
= TRUE
; break;
51 write(2,"Usage: tr [-cds] [string1 [string2]].\n", 38);
57 for (i
= 0; i
<= ASCII
; i
++) {
59 invec
[i
] = outvec
[i
] = FALSE
;
62 if (argv
[index
] != NIL_PTR
) {
63 expand(argv
[index
++], input
);
64 if (com_fl
) complement(input
);
65 if (argv
[index
] != NIL_PTR
) expand(argv
[index
], output
);
66 if (argv
[index
] != NIL_PTR
) map(input
, output
);
67 for (ptr
= input
; *ptr
; ptr
++) invec
[*ptr
] = TRUE
;
68 for (ptr
= output
; *ptr
; ptr
++) outvec
[*ptr
] = TRUE
;
81 if (in_index
== read_chars
) {
82 if ((read_chars
= read(0, (char *)input
, BUFFER_SIZE
)) <= 0) {
83 if (write(1, (char *)output
, out_index
) != out_index
)
84 write(2, "Bad write\n", 10);
89 c
= input
[in_index
++];
91 if (del_fl
&& invec
[c
]) continue;
92 if (sq_fl
&& last
== coded
&& outvec
[coded
]) continue;
93 output
[out_index
++] = last
= coded
;
94 if (out_index
== BUFFER_SIZE
) {
95 if (write(1, (char *)output
, out_index
) != out_index
) {
96 write(2, "Bad write\n", 10);
106 void map(string1
, string2
)
107 register unsigned char *string1
, *string2
;
112 if (*string2
== '\0')
113 vector
[*string1
] = last
;
115 vector
[*string1
] = last
= *string2
++;
120 static int starts_with(const char *s1
, const char *s2
)
122 while (*s1
&& *s1
== *s2
)
131 * character classes from
132 * http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html
133 * missing: blank, punct, cntrl, graph, print, space
140 } expand_keywords
[] = {
141 { "[:alnum:]", 'A', 'Z' },
142 { "[:alnum:]", 'a', 'z' },
143 { "[:alnum:]", '0', '9' },
144 { "[:alpha:]", 'A', 'Z' },
145 { "[:alpha:]", 'a', 'z' },
146 { "[:digit:]", '0', '9' },
147 { "[:lower:]", 'a', 'z' },
148 { "[:upper:]", 'A', 'Z' },
149 { "[:xdigit:]", '0', '9' },
150 { "[:xdigit:]", 'A', 'F' },
151 { "[:xdigit:]", 'a', 'f' }
154 #define LENGTH(a) ((sizeof((a))) / (sizeof((a)[0])))
156 void expand(arg
, buffer
)
158 register unsigned char *buffer
;
160 int i
, ac
, keyword_index
;
166 if (*arg
>= '0' && *arg
<= '7') {
168 ac
= (ac
<< 3) + *arg
++ - '0';
170 } while (i
< 4 && *arg
>= '0' && *arg
<= '7');
172 } else if (*arg
!= '\0')
174 } else if (*arg
== '[') {
175 /* does one of the keywords match? */
177 for (i
= 0; i
< LENGTH(expand_keywords
); i
++)
178 if (starts_with(expand_keywords
[i
].keyword
, arg
))
180 /* we have a match, remember and expand */
182 ac
= expand_keywords
[i
].first
;
183 while (ac
<= expand_keywords
[i
].last
)
187 /* skip keyword if found, otherwise expand range */
188 if (keyword_index
>= 0)
189 arg
+= strlen(expand_keywords
[keyword_index
].keyword
);
201 while (i
<= ac
) *buffer
++ = i
++;
202 arg
++; /* Skip ']' */
209 void complement(buffer
)
210 unsigned char *buffer
;
212 register unsigned char *ptr
;
213 register short i
, index
;
214 unsigned char conv
[ASCII
+ 2];
217 for (i
= 1; i
<= ASCII
; i
++) {
218 for (ptr
= buffer
; *ptr
; ptr
++)
219 if (*ptr
== i
) break;
220 if (*ptr
== '\0') conv
[index
++] = i
& ASCII
;
223 strcpy((char *)buffer
, (char *)conv
);