Add character classes for tr
This commit is contained in:
parent
6b869823ae
commit
58024f9eb0
2 changed files with 74 additions and 10 deletions
|
@ -117,11 +117,47 @@ register unsigned char *string1, *string2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int starts_with(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
while (*s1 && *s1 == *s2)
|
||||||
|
{
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
}
|
||||||
|
return *s1 == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* character classes from
|
||||||
|
* http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html
|
||||||
|
* missing: blank, punct, cntrl, graph, print, space
|
||||||
|
*/
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
const char *keyword;
|
||||||
|
char first;
|
||||||
|
char last;
|
||||||
|
} expand_keywords[] = {
|
||||||
|
{ "[:alnum:]", 'A', 'Z' },
|
||||||
|
{ "[:alnum:]", 'a', 'z' },
|
||||||
|
{ "[:alnum:]", '0', '9' },
|
||||||
|
{ "[:alpha:]", 'A', 'Z' },
|
||||||
|
{ "[:alpha:]", 'a', 'z' },
|
||||||
|
{ "[:digit:]", '0', '9' },
|
||||||
|
{ "[:lower:]", 'a', 'z' },
|
||||||
|
{ "[:upper:]", 'A', 'Z' },
|
||||||
|
{ "[:xdigit:]", '0', '9' },
|
||||||
|
{ "[:xdigit:]", 'A', 'F' },
|
||||||
|
{ "[:xdigit:]", 'a', 'f' }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LENGTH(a) ((sizeof((a))) / (sizeof((a)[0])))
|
||||||
|
|
||||||
void expand(arg, buffer)
|
void expand(arg, buffer)
|
||||||
register char *arg;
|
register char *arg;
|
||||||
register unsigned char *buffer;
|
register unsigned char *buffer;
|
||||||
{
|
{
|
||||||
int i, ac;
|
int i, ac, keyword_index;
|
||||||
|
|
||||||
while (*arg) {
|
while (*arg) {
|
||||||
if (*arg == '\\') {
|
if (*arg == '\\') {
|
||||||
|
@ -136,16 +172,35 @@ register unsigned char *buffer;
|
||||||
} else if (*arg != '\0')
|
} else if (*arg != '\0')
|
||||||
*buffer++ = *arg++;
|
*buffer++ = *arg++;
|
||||||
} else if (*arg == '[') {
|
} else if (*arg == '[') {
|
||||||
arg++;
|
/* does one of the keywords match? */
|
||||||
i = *arg++;
|
keyword_index = -1;
|
||||||
if (*arg++ != '-') {
|
for (i = 0; i < LENGTH(expand_keywords); i++)
|
||||||
*buffer++ = '[';
|
if (starts_with(expand_keywords[i].keyword, arg))
|
||||||
arg -= 2;
|
{
|
||||||
continue;
|
/* we have a match, remember and expand */
|
||||||
|
keyword_index = i;
|
||||||
|
ac = expand_keywords[i].first;
|
||||||
|
while (ac <= expand_keywords[i].last)
|
||||||
|
*buffer++ = ac++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip keyword if found, otherwise expand range */
|
||||||
|
if (keyword_index >= 0)
|
||||||
|
arg += strlen(expand_keywords[keyword_index].keyword);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* expand range */
|
||||||
|
arg++;
|
||||||
|
i = *arg++;
|
||||||
|
if (*arg++ != '-') {
|
||||||
|
*buffer++ = '[';
|
||||||
|
arg -= 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ac = *arg++;
|
||||||
|
while (i <= ac) *buffer++ = i++;
|
||||||
|
arg++; /* Skip ']' */
|
||||||
}
|
}
|
||||||
ac = *arg++;
|
|
||||||
while (i <= ac) *buffer++ = i++;
|
|
||||||
arg++; /* Skip ']' */
|
|
||||||
} else
|
} else
|
||||||
*buffer++ = *arg++;
|
*buffer++ = *arg++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,3 +45,12 @@ Use [ and ] if you want to be portable, because a
|
||||||
.I tr
|
.I tr
|
||||||
that doesn't need them will still accept the syntax and mindlessly
|
that doesn't need them will still accept the syntax and mindlessly
|
||||||
translate [ into [ and ] into ].
|
translate [ into [ and ] into ].
|
||||||
|
.PP
|
||||||
|
MINIX tr supports the following character classes: alnum, alpha, digit, lower,
|
||||||
|
upper and xdigit. If any of these keywords is encountered between backets and
|
||||||
|
colons, it is replaced by respectively alphanumeric characters, alphabetic
|
||||||
|
characters, decimal digits, lowercase letters, uppercase letters and
|
||||||
|
hexadecimal digits. The following are equivalent with the given examples:
|
||||||
|
.EX "tr \(fm[:upper:]\(fm \(fm[:lower:]\(fm <x >y " "Convert upper case to lower case"
|
||||||
|
.EX "tr \-d \(fm[:digit:]\(fm <f1 >f2 " "Delete all digits from \fIf1\fR"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue