From fb002d0df02ce53e8bcc03fe6e451b250b4d519e Mon Sep 17 00:00:00 2001 From: Erik Andersen Date: Sun, 5 Mar 2000 08:07:00 +0000 Subject: [PATCH] Add in tr and dirname -Erik --- AUTHORS | 3 + Changelog | 1 + applets/busybox.c | 6 + busybox.c | 6 + busybox.def.h | 2 + coreutils/dirname.c | 146 +++++++++++ coreutils/tr.c | 578 ++++++++++++++++++++++++++++++++++++++++++++ dirname.c | 146 +++++++++++ internal.h | 2 + tr.c | 578 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1468 insertions(+) create mode 100644 coreutils/dirname.c create mode 100644 coreutils/tr.c create mode 100644 dirname.c create mode 100644 tr.c diff --git a/AUTHORS b/AUTHORS index 526205b49..9d7cb0825 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,6 +28,9 @@ Dave Cinege more(v2), makedevs, dutmp, modularization, auto links file, various fixes, Linux Router Project maintenance +John Lombardo + dirname, tr + Linus Torvalds mkswap, fsck.minix, mkfs.minix diff --git a/Changelog b/Changelog index c671f7a80..14524410c 100644 --- a/Changelog +++ b/Changelog @@ -3,6 +3,7 @@ * Added freeramdisk, which will free up all memory associated with a ram disk. Contributed by Emanuele Caratti and then adjusted a bit by me. + * Added tr and dirname from John Lombardo * tar wouldn't create directory entries that don't end in '/', now it does (thanks to Avery Pennarun ) * Several fixes from Pavel Roskin : diff --git a/applets/busybox.c b/applets/busybox.c index 991801310..36cf0a05c 100644 --- a/applets/busybox.c +++ b/applets/busybox.c @@ -76,6 +76,9 @@ static const struct Applet applets[] = { #ifdef BB_DF //bin {"df", df_main}, #endif +#ifdef BB_DIRNAME //usr/bin + {"dirname", dirname_main}, +#endif #ifdef BB_DMESG //bin {"dmesg", dmesg_main}, #endif @@ -261,6 +264,9 @@ static const struct Applet applets[] = { #ifdef BB_TOUCH //usr/bin {"touch", touch_main}, #endif +#ifdef BB_TR //usr/bin + {"tr", tr_main}, +#endif #ifdef BB_TRUE_FALSE //bin {"true", true_main}, {"false", false_main}, diff --git a/busybox.c b/busybox.c index 991801310..36cf0a05c 100644 --- a/busybox.c +++ b/busybox.c @@ -76,6 +76,9 @@ static const struct Applet applets[] = { #ifdef BB_DF //bin {"df", df_main}, #endif +#ifdef BB_DIRNAME //usr/bin + {"dirname", dirname_main}, +#endif #ifdef BB_DMESG //bin {"dmesg", dmesg_main}, #endif @@ -261,6 +264,9 @@ static const struct Applet applets[] = { #ifdef BB_TOUCH //usr/bin {"touch", touch_main}, #endif +#ifdef BB_TR //usr/bin + {"tr", tr_main}, +#endif #ifdef BB_TRUE_FALSE //bin {"true", true_main}, {"false", false_main}, diff --git a/busybox.def.h b/busybox.def.h index b82bcc5f1..306133ba8 100644 --- a/busybox.def.h +++ b/busybox.def.h @@ -18,6 +18,7 @@ #define BB_DD #define BB_DEALLOCVT #define BB_DF +#define BB_DIRNAME #define BB_DMESG //#define BB_DUTMP #define BB_DU @@ -84,6 +85,7 @@ // Don't turn BB_TELNET on. It doesn't work. #define BB_TELNET #define BB_TOUCH +#define BB_TR #define BB_TRUE_FALSE #define BB_TTY #define BB_UPTIME diff --git a/coreutils/dirname.c b/coreutils/dirname.c new file mode 100644 index 000000000..77cb664ac --- /dev/null +++ b/coreutils/dirname.c @@ -0,0 +1,146 @@ +/* vi: set sw=4 ts=4: */ +/* + * This is temporary -- needs to be rewritten to be tighter */ +/* + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95"; +#endif /* not lint */ +#endif /* #if 0 */ + +#include "internal.h" +#include +#include +#include + +void dirname_usage() +{ + + (void) fprintf(stderr, "usage: dirname path\n"); + exit(1); +} + +extern int dirname_main(argc, argv) +int argc; +char **argv; +{ + char *p; + int ch; + + while ((ch = getopt(argc, argv, "")) != -1) + switch (ch) { + case '?': + default: + dirname_usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + dirname_usage(); + + /* + * (1) If string is //, skip steps (2) through (5). + * (2) If string consists entirely of slash characters, string + * shall be set to a single slash character. In this case, + * skip steps (3) through (8). + */ + for (p = *argv;; ++p) { + if (!*p) { + if (p > *argv) + (void) printf("/\n"); + else + (void) printf(".\n"); + exit(0); + } + if (*p != '/') + break; + } + + /* + * (3) If there are any trailing slash characters in string, they + * shall be removed. + */ + for (; *p; ++p); + while (*--p == '/') + continue; + *++p = '\0'; + + /* + * (4) If there are no slash characters remaining in string, + * string shall be set to a single period character. In this + * case skip steps (5) through (8). + * + * (5) If there are any trailing nonslash characters in string, + * they shall be removed. + */ + while (--p >= *argv) + if (*p == '/') + break; + ++p; + if (p == *argv) { + (void) printf(".\n"); + exit(0); + } + + /* + * (6) If the remaining string is //, it is implementation defined + * whether steps (7) and (8) are skipped or processed. + * + * This case has already been handled, as part of steps (1) and (2). + */ + + /* + * (7) If there are any trailing slash characters in string, they + * shall be removed. + */ + while (--p >= *argv) + if (*p != '/') + break; + ++p; + + /* + * (8) If the remaining string is empty, string shall be set to + * a single slash character. + */ + *p = '\0'; + (void) printf("%s\n", p == *argv ? "/" : *argv); + exit(0); +} diff --git a/coreutils/tr.c b/coreutils/tr.c new file mode 100644 index 000000000..8ac09e641 --- /dev/null +++ b/coreutils/tr.c @@ -0,0 +1,578 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95"; +#endif +static const char rcsid[] = + + "$Id: tr.c,v 1.1 2000/03/05 08:07:00 erik Exp $"; +#endif /* not lint */ +#endif /* #if 0 */ + +#include "internal.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef struct { + enum { STRING1, STRING2 } which; + enum { EOS, INFINITE, NORMAL, RANGE, SEQUENCE, SET } state; + int cnt; /* character count */ + int lastch; /* last character */ + int equiv[2]; /* equivalence set */ + int *set; /* set of characters */ + char *str; /* user's string */ +} STR; + +#include +#define NCHARS (UCHAR_MAX + 1) /* Number of possible characters. */ +#define OOBCH (UCHAR_MAX + 1) /* Out of band character value. */ + +static int next __P((STR *)); + +static int string1[NCHARS] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ASCII */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}, string2[NCHARS]; + +STR s1 = { STRING1, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; +STR s2 = { STRING2, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; + +static void setup(string, arg, str, cflag) +int *string; +char *arg; +STR *str; +int cflag; +{ + register int cnt, *p; + + str->str = arg; + bzero(string, NCHARS * sizeof(int)); + + while (next(str)) + string[str->lastch] = 1; + if (cflag) + for (p = string, cnt = NCHARS; cnt--; ++p) + *p = !*p; +} + +static void tr_usage() +{ + (void) fprintf(stderr, "%s\n%s\n%s\n%s\n", + "usage: tr [-csu] string1 string2", + " tr [-cu] -d string1", + " tr [-cu] -s string1", + " tr [-cu] -ds string1 string2"); + exit(1); +} + + +extern int tr_main(argc, argv) +int argc; +char **argv; +{ + register int ch, cnt, lastch, *p; + int cflag, dflag, sflag, isstring2; + + (void) setlocale(LC_CTYPE, ""); + + cflag = dflag = sflag = 0; + while ((ch = getopt(argc, argv, "cdsu")) != -1) + switch ((char) ch) { + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 's': + sflag = 1; + break; + case 'u': + setbuf(stdout, (char *) NULL); + break; + case '?': + default: + tr_usage(); + } + argc -= optind; + argv += optind; + + switch (argc) { + case 0: + default: + tr_usage(); + /* NOTREACHED */ + case 1: + isstring2 = 0; + break; + case 2: + isstring2 = 1; + break; + } + + /* + * tr -ds [-c] string1 string2 + * Delete all characters (or complemented characters) in string1. + * Squeeze all characters in string2. + */ + if (dflag && sflag) { + if (!isstring2) + tr_usage(); + + setup(string1, argv[0], &s1, cflag); + setup(string2, argv[1], &s2, 0); + + for (lastch = OOBCH; (ch = getchar()) != EOF;) + if (!string1[ch] && (!string2[ch] || lastch != ch)) { + lastch = ch; + (void) putchar(ch); + } + exit(0); + } + + /* + * tr -d [-c] string1 + * Delete all characters (or complemented characters) in string1. + */ + if (dflag) { + if (isstring2) + tr_usage(); + + setup(string1, argv[0], &s1, cflag); + + while ((ch = getchar()) != EOF) + if (!string1[ch]) + (void) putchar(ch); + exit(0); + } + + /* + * tr -s [-c] string1 + * Squeeze all characters (or complemented characters) in string1. + */ + if (sflag && !isstring2) { + setup(string1, argv[0], &s1, cflag); + + for (lastch = OOBCH; (ch = getchar()) != EOF;) + if (!string1[ch] || lastch != ch) { + lastch = ch; + (void) putchar(ch); + } + exit(0); + } + + /* + * tr [-cs] string1 string2 + * Replace all characters (or complemented characters) in string1 with + * the character in the same position in string2. If the -s option is + * specified, squeeze all the characters in string2. + */ + if (!isstring2) + tr_usage(); + + s1.str = argv[0]; + s2.str = argv[1]; + + if (cflag) + for (cnt = NCHARS, p = string1; cnt--;) + *p++ = OOBCH; + + if (!next(&s2)) + errx(1, "empty string2"); + + /* If string2 runs out of characters, use the last one specified. */ + if (sflag) + while (next(&s1)) { + string1[s1.lastch] = ch = s2.lastch; + string2[ch] = 1; + (void) next(&s2); + } else + while (next(&s1)) { + string1[s1.lastch] = ch = s2.lastch; + (void) next(&s2); + } + + if (cflag) + for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt) + *p = *p == OOBCH ? ch : cnt; + + if (sflag) + for (lastch = OOBCH; (ch = getchar()) != EOF;) { + ch = string1[ch]; + if (!string2[ch] || lastch != ch) { + lastch = ch; + (void) putchar(ch); + } + } else + while ((ch = getchar()) != EOF) + (void) putchar(string1[ch]); + exit(0); +} + +static int backslash __P((STR *)); +static int bracket __P((STR *)); +static int c_class __P((const void *, const void *)); +static void genclass __P((STR *)); +static void genequiv __P((STR *)); +static int genrange __P((STR *)); +static void genseq __P((STR *)); + +static int next(s) +register STR *s; +{ + register int ch; + + switch (s->state) { + case EOS: + return (0); + case INFINITE: + return (1); + case NORMAL: + switch (ch = (u_char) * s->str) { + case '\0': + s->state = EOS; + return (0); + case '\\': + s->lastch = backslash(s); + break; + case '[': + if (bracket(s)) + return (next(s)); + /* FALLTHROUGH */ + default: + ++s->str; + s->lastch = ch; + break; + } + + /* We can start a range at any time. */ + if (s->str[0] == '-' && genrange(s)) + return (next(s)); + return (1); + case RANGE: + if (s->cnt-- == 0) { + s->state = NORMAL; + return (next(s)); + } + ++s->lastch; + return (1); + case SEQUENCE: + if (s->cnt-- == 0) { + s->state = NORMAL; + return (next(s)); + } + return (1); + case SET: + if ((s->lastch = s->set[s->cnt++]) == OOBCH) { + s->state = NORMAL; + return (next(s)); + } + return (1); + } + /* NOTREACHED */ + return (0); +} + +static int bracket(s) +register STR *s; +{ + register char *p; + + switch (s->str[1]) { + case ':': /* "[:class:]" */ + if ((p = strstr(s->str + 2, ":]")) == NULL) + return (0); + *p = '\0'; + s->str += 2; + genclass(s); + s->str = p + 2; + return (1); + case '=': /* "[=equiv=]" */ + if ((p = strstr(s->str + 2, "=]")) == NULL) + return (0); + s->str += 2; + genequiv(s); + return (1); + default: /* "[\###*n]" or "[#*n]" */ + if ((p = strpbrk(s->str + 2, "*]")) == NULL) + return (0); + if (p[0] != '*' || index(p, ']') == NULL) + return (0); + s->str += 1; + genseq(s); + return (1); + } + /* NOTREACHED */ +} + +typedef struct { + char *name; + int (*func) __P((int)); + int *set; +} CLASS; + +static CLASS classes[] = { +#undef isalnum + {"alnum", isalnum,}, +#undef isalpha + {"alpha", isalpha,}, +/*#undef isblank + { "blank", isblank, },*/ +#undef iscntrl + {"cntrl", iscntrl,}, +#undef isdigit + {"digit", isdigit,}, +#undef isgraph + {"graph", isgraph,}, +#undef islower + {"lower", islower,}, +#undef isprint + {"print", isprint,}, +#undef ispunct + {"punct", ispunct,}, +#undef isspace + {"space", isspace,}, +#undef isupper + {"upper", isupper,}, +#undef isxdigit + {"xdigit", isxdigit,}, +}; + +static void genclass(s) +STR *s; +{ + register int cnt, (*func) __P((int)); + CLASS *cp, tmp; + int *p; + + tmp.name = s->str; + if ((cp = (CLASS *) bsearch(&tmp, classes, sizeof(classes) / + sizeof(CLASS), sizeof(CLASS), + c_class)) == NULL) errx(1, + "unknown class %s", + s->str); + + if ((cp->set = p = malloc((NCHARS + 1) * sizeof(int))) == NULL) + errx(1, "malloc"); + bzero(p, (NCHARS + 1) * sizeof(int)); + + for (cnt = 0, func = cp->func; cnt < NCHARS; ++cnt) + if ((func) (cnt)) + *p++ = cnt; + *p = OOBCH; + + s->cnt = 0; + s->state = SET; + s->set = cp->set; +} + +static int c_class(a, b) +const void *a, *b; +{ + return (strcmp(((CLASS *) a)->name, ((CLASS *) b)->name)); +} + +/* + * English doesn't have any equivalence classes, so for now + * we just syntax check and grab the character. + */ +static void genequiv(s) +STR *s; +{ + if (*s->str == '\\') { + s->equiv[0] = backslash(s); + if (*s->str != '=') + errx(1, "misplaced equivalence equals sign"); + } else { + s->equiv[0] = s->str[0]; + if (s->str[1] != '=') + errx(1, "misplaced equivalence equals sign"); + } + s->str += 2; + s->cnt = 0; + s->state = SET; + s->set = s->equiv; +} + +static int genrange(s) +STR *s; +{ + int stopval; + char *savestart; + + savestart = s->str; + stopval = *++s->str == '\\' ? backslash(s) : (u_char) * s->str++; + if (stopval < (u_char) s->lastch) { + s->str = savestart; + return (0); + } + s->cnt = stopval - s->lastch + 1; + s->state = RANGE; + --s->lastch; + return (1); +} + +static void genseq(s) +STR *s; +{ + char *ep; + + if (s->which == STRING1) + errx(1, "sequences only valid in string2"); + + if (*s->str == '\\') + s->lastch = backslash(s); + else + s->lastch = *s->str++; + if (*s->str != '*') + errx(1, "misplaced sequence asterisk"); + + switch (*++s->str) { + case '\\': + s->cnt = backslash(s); + break; + case ']': + s->cnt = 0; + ++s->str; + break; + default: + if (isdigit((u_char) * s->str)) { + s->cnt = strtol(s->str, &ep, 0); + if (*ep == ']') { + s->str = ep + 1; + break; + } + } + errx(1, "illegal sequence count"); + /* NOTREACHED */ + } + + s->state = s->cnt ? SEQUENCE : INFINITE; +} + +/* + * Translate \??? into a character. Up to 3 octal digits, if no digits either + * an escape code or a literal character. + */ +static int backslash(s) +register STR *s; +{ + register int ch, cnt, val; + + for (cnt = val = 0;;) { + ch = (u_char) * ++s->str; + if (!isascii(ch) || !isdigit(ch)) + break; + val = val * 8 + ch - '0'; + if (++cnt == 3) { + ++s->str; + break; + } + } + if (cnt) + return (val); + if (ch != '\0') + ++s->str; + switch (ch) { + case 'a': /* escape characters */ + return ('\7'); + case 'b': + return ('\b'); + case 'f': + return ('\f'); + case 'n': + return ('\n'); + case 'r': + return ('\r'); + case 't': + return ('\t'); + case 'v': + return ('\13'); + case '\0': /* \" -> \ */ + s->state = EOS; + return ('\\'); + default: /* \x" -> x */ + return (ch); + } +} diff --git a/dirname.c b/dirname.c new file mode 100644 index 000000000..77cb664ac --- /dev/null +++ b/dirname.c @@ -0,0 +1,146 @@ +/* vi: set sw=4 ts=4: */ +/* + * This is temporary -- needs to be rewritten to be tighter */ +/* + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95"; +#endif /* not lint */ +#endif /* #if 0 */ + +#include "internal.h" +#include +#include +#include + +void dirname_usage() +{ + + (void) fprintf(stderr, "usage: dirname path\n"); + exit(1); +} + +extern int dirname_main(argc, argv) +int argc; +char **argv; +{ + char *p; + int ch; + + while ((ch = getopt(argc, argv, "")) != -1) + switch (ch) { + case '?': + default: + dirname_usage(); + } + argc -= optind; + argv += optind; + + if (argc != 1) + dirname_usage(); + + /* + * (1) If string is //, skip steps (2) through (5). + * (2) If string consists entirely of slash characters, string + * shall be set to a single slash character. In this case, + * skip steps (3) through (8). + */ + for (p = *argv;; ++p) { + if (!*p) { + if (p > *argv) + (void) printf("/\n"); + else + (void) printf(".\n"); + exit(0); + } + if (*p != '/') + break; + } + + /* + * (3) If there are any trailing slash characters in string, they + * shall be removed. + */ + for (; *p; ++p); + while (*--p == '/') + continue; + *++p = '\0'; + + /* + * (4) If there are no slash characters remaining in string, + * string shall be set to a single period character. In this + * case skip steps (5) through (8). + * + * (5) If there are any trailing nonslash characters in string, + * they shall be removed. + */ + while (--p >= *argv) + if (*p == '/') + break; + ++p; + if (p == *argv) { + (void) printf(".\n"); + exit(0); + } + + /* + * (6) If the remaining string is //, it is implementation defined + * whether steps (7) and (8) are skipped or processed. + * + * This case has already been handled, as part of steps (1) and (2). + */ + + /* + * (7) If there are any trailing slash characters in string, they + * shall be removed. + */ + while (--p >= *argv) + if (*p != '/') + break; + ++p; + + /* + * (8) If the remaining string is empty, string shall be set to + * a single slash character. + */ + *p = '\0'; + (void) printf("%s\n", p == *argv ? "/" : *argv); + exit(0); +} diff --git a/internal.h b/internal.h index 7ae129729..fcb24dc14 100644 --- a/internal.h +++ b/internal.h @@ -68,6 +68,7 @@ extern int chvt_main(int argc, char** argv); extern int clear_main(int argc, char** argv); extern int date_main(int argc, char** argv); extern int dd_main(int argc, char** argv); +extern int dirname_main(int argc, char** argv); extern int deallocvt_main(int argc, char** argv); extern int df_main(int argc, char** argv); extern int dmesg_main(int argc, char** argv); @@ -134,6 +135,7 @@ extern int tar_main(int argc, char** argv); extern int tee_main(int argc, char** argv); extern int telnet_main(int argc, char** argv); extern int touch_main(int argc, char** argv); +extern int tr_main(int argc, char** argv); extern int true_main(int argc, char** argv); extern int tput_main(int argc, char** argv); extern int tryopen_main(int argc, char** argv); diff --git a/tr.c b/tr.c new file mode 100644 index 000000000..8ac09e641 --- /dev/null +++ b/tr.c @@ -0,0 +1,578 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95"; +#endif +static const char rcsid[] = + + "$Id: tr.c,v 1.1 2000/03/05 08:07:00 erik Exp $"; +#endif /* not lint */ +#endif /* #if 0 */ + +#include "internal.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef struct { + enum { STRING1, STRING2 } which; + enum { EOS, INFINITE, NORMAL, RANGE, SEQUENCE, SET } state; + int cnt; /* character count */ + int lastch; /* last character */ + int equiv[2]; /* equivalence set */ + int *set; /* set of characters */ + char *str; /* user's string */ +} STR; + +#include +#define NCHARS (UCHAR_MAX + 1) /* Number of possible characters. */ +#define OOBCH (UCHAR_MAX + 1) /* Out of band character value. */ + +static int next __P((STR *)); + +static int string1[NCHARS] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ASCII */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}, string2[NCHARS]; + +STR s1 = { STRING1, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; +STR s2 = { STRING2, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; + +static void setup(string, arg, str, cflag) +int *string; +char *arg; +STR *str; +int cflag; +{ + register int cnt, *p; + + str->str = arg; + bzero(string, NCHARS * sizeof(int)); + + while (next(str)) + string[str->lastch] = 1; + if (cflag) + for (p = string, cnt = NCHARS; cnt--; ++p) + *p = !*p; +} + +static void tr_usage() +{ + (void) fprintf(stderr, "%s\n%s\n%s\n%s\n", + "usage: tr [-csu] string1 string2", + " tr [-cu] -d string1", + " tr [-cu] -s string1", + " tr [-cu] -ds string1 string2"); + exit(1); +} + + +extern int tr_main(argc, argv) +int argc; +char **argv; +{ + register int ch, cnt, lastch, *p; + int cflag, dflag, sflag, isstring2; + + (void) setlocale(LC_CTYPE, ""); + + cflag = dflag = sflag = 0; + while ((ch = getopt(argc, argv, "cdsu")) != -1) + switch ((char) ch) { + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 's': + sflag = 1; + break; + case 'u': + setbuf(stdout, (char *) NULL); + break; + case '?': + default: + tr_usage(); + } + argc -= optind; + argv += optind; + + switch (argc) { + case 0: + default: + tr_usage(); + /* NOTREACHED */ + case 1: + isstring2 = 0; + break; + case 2: + isstring2 = 1; + break; + } + + /* + * tr -ds [-c] string1 string2 + * Delete all characters (or complemented characters) in string1. + * Squeeze all characters in string2. + */ + if (dflag && sflag) { + if (!isstring2) + tr_usage(); + + setup(string1, argv[0], &s1, cflag); + setup(string2, argv[1], &s2, 0); + + for (lastch = OOBCH; (ch = getchar()) != EOF;) + if (!string1[ch] && (!string2[ch] || lastch != ch)) { + lastch = ch; + (void) putchar(ch); + } + exit(0); + } + + /* + * tr -d [-c] string1 + * Delete all characters (or complemented characters) in string1. + */ + if (dflag) { + if (isstring2) + tr_usage(); + + setup(string1, argv[0], &s1, cflag); + + while ((ch = getchar()) != EOF) + if (!string1[ch]) + (void) putchar(ch); + exit(0); + } + + /* + * tr -s [-c] string1 + * Squeeze all characters (or complemented characters) in string1. + */ + if (sflag && !isstring2) { + setup(string1, argv[0], &s1, cflag); + + for (lastch = OOBCH; (ch = getchar()) != EOF;) + if (!string1[ch] || lastch != ch) { + lastch = ch; + (void) putchar(ch); + } + exit(0); + } + + /* + * tr [-cs] string1 string2 + * Replace all characters (or complemented characters) in string1 with + * the character in the same position in string2. If the -s option is + * specified, squeeze all the characters in string2. + */ + if (!isstring2) + tr_usage(); + + s1.str = argv[0]; + s2.str = argv[1]; + + if (cflag) + for (cnt = NCHARS, p = string1; cnt--;) + *p++ = OOBCH; + + if (!next(&s2)) + errx(1, "empty string2"); + + /* If string2 runs out of characters, use the last one specified. */ + if (sflag) + while (next(&s1)) { + string1[s1.lastch] = ch = s2.lastch; + string2[ch] = 1; + (void) next(&s2); + } else + while (next(&s1)) { + string1[s1.lastch] = ch = s2.lastch; + (void) next(&s2); + } + + if (cflag) + for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt) + *p = *p == OOBCH ? ch : cnt; + + if (sflag) + for (lastch = OOBCH; (ch = getchar()) != EOF;) { + ch = string1[ch]; + if (!string2[ch] || lastch != ch) { + lastch = ch; + (void) putchar(ch); + } + } else + while ((ch = getchar()) != EOF) + (void) putchar(string1[ch]); + exit(0); +} + +static int backslash __P((STR *)); +static int bracket __P((STR *)); +static int c_class __P((const void *, const void *)); +static void genclass __P((STR *)); +static void genequiv __P((STR *)); +static int genrange __P((STR *)); +static void genseq __P((STR *)); + +static int next(s) +register STR *s; +{ + register int ch; + + switch (s->state) { + case EOS: + return (0); + case INFINITE: + return (1); + case NORMAL: + switch (ch = (u_char) * s->str) { + case '\0': + s->state = EOS; + return (0); + case '\\': + s->lastch = backslash(s); + break; + case '[': + if (bracket(s)) + return (next(s)); + /* FALLTHROUGH */ + default: + ++s->str; + s->lastch = ch; + break; + } + + /* We can start a range at any time. */ + if (s->str[0] == '-' && genrange(s)) + return (next(s)); + return (1); + case RANGE: + if (s->cnt-- == 0) { + s->state = NORMAL; + return (next(s)); + } + ++s->lastch; + return (1); + case SEQUENCE: + if (s->cnt-- == 0) { + s->state = NORMAL; + return (next(s)); + } + return (1); + case SET: + if ((s->lastch = s->set[s->cnt++]) == OOBCH) { + s->state = NORMAL; + return (next(s)); + } + return (1); + } + /* NOTREACHED */ + return (0); +} + +static int bracket(s) +register STR *s; +{ + register char *p; + + switch (s->str[1]) { + case ':': /* "[:class:]" */ + if ((p = strstr(s->str + 2, ":]")) == NULL) + return (0); + *p = '\0'; + s->str += 2; + genclass(s); + s->str = p + 2; + return (1); + case '=': /* "[=equiv=]" */ + if ((p = strstr(s->str + 2, "=]")) == NULL) + return (0); + s->str += 2; + genequiv(s); + return (1); + default: /* "[\###*n]" or "[#*n]" */ + if ((p = strpbrk(s->str + 2, "*]")) == NULL) + return (0); + if (p[0] != '*' || index(p, ']') == NULL) + return (0); + s->str += 1; + genseq(s); + return (1); + } + /* NOTREACHED */ +} + +typedef struct { + char *name; + int (*func) __P((int)); + int *set; +} CLASS; + +static CLASS classes[] = { +#undef isalnum + {"alnum", isalnum,}, +#undef isalpha + {"alpha", isalpha,}, +/*#undef isblank + { "blank", isblank, },*/ +#undef iscntrl + {"cntrl", iscntrl,}, +#undef isdigit + {"digit", isdigit,}, +#undef isgraph + {"graph", isgraph,}, +#undef islower + {"lower", islower,}, +#undef isprint + {"print", isprint,}, +#undef ispunct + {"punct", ispunct,}, +#undef isspace + {"space", isspace,}, +#undef isupper + {"upper", isupper,}, +#undef isxdigit + {"xdigit", isxdigit,}, +}; + +static void genclass(s) +STR *s; +{ + register int cnt, (*func) __P((int)); + CLASS *cp, tmp; + int *p; + + tmp.name = s->str; + if ((cp = (CLASS *) bsearch(&tmp, classes, sizeof(classes) / + sizeof(CLASS), sizeof(CLASS), + c_class)) == NULL) errx(1, + "unknown class %s", + s->str); + + if ((cp->set = p = malloc((NCHARS + 1) * sizeof(int))) == NULL) + errx(1, "malloc"); + bzero(p, (NCHARS + 1) * sizeof(int)); + + for (cnt = 0, func = cp->func; cnt < NCHARS; ++cnt) + if ((func) (cnt)) + *p++ = cnt; + *p = OOBCH; + + s->cnt = 0; + s->state = SET; + s->set = cp->set; +} + +static int c_class(a, b) +const void *a, *b; +{ + return (strcmp(((CLASS *) a)->name, ((CLASS *) b)->name)); +} + +/* + * English doesn't have any equivalence classes, so for now + * we just syntax check and grab the character. + */ +static void genequiv(s) +STR *s; +{ + if (*s->str == '\\') { + s->equiv[0] = backslash(s); + if (*s->str != '=') + errx(1, "misplaced equivalence equals sign"); + } else { + s->equiv[0] = s->str[0]; + if (s->str[1] != '=') + errx(1, "misplaced equivalence equals sign"); + } + s->str += 2; + s->cnt = 0; + s->state = SET; + s->set = s->equiv; +} + +static int genrange(s) +STR *s; +{ + int stopval; + char *savestart; + + savestart = s->str; + stopval = *++s->str == '\\' ? backslash(s) : (u_char) * s->str++; + if (stopval < (u_char) s->lastch) { + s->str = savestart; + return (0); + } + s->cnt = stopval - s->lastch + 1; + s->state = RANGE; + --s->lastch; + return (1); +} + +static void genseq(s) +STR *s; +{ + char *ep; + + if (s->which == STRING1) + errx(1, "sequences only valid in string2"); + + if (*s->str == '\\') + s->lastch = backslash(s); + else + s->lastch = *s->str++; + if (*s->str != '*') + errx(1, "misplaced sequence asterisk"); + + switch (*++s->str) { + case '\\': + s->cnt = backslash(s); + break; + case ']': + s->cnt = 0; + ++s->str; + break; + default: + if (isdigit((u_char) * s->str)) { + s->cnt = strtol(s->str, &ep, 0); + if (*ep == ']') { + s->str = ep + 1; + break; + } + } + errx(1, "illegal sequence count"); + /* NOTREACHED */ + } + + s->state = s->cnt ? SEQUENCE : INFINITE; +} + +/* + * Translate \??? into a character. Up to 3 octal digits, if no digits either + * an escape code or a literal character. + */ +static int backslash(s) +register STR *s; +{ + register int ch, cnt, val; + + for (cnt = val = 0;;) { + ch = (u_char) * ++s->str; + if (!isascii(ch) || !isdigit(ch)) + break; + val = val * 8 + ch - '0'; + if (++cnt == 3) { + ++s->str; + break; + } + } + if (cnt) + return (val); + if (ch != '\0') + ++s->str; + switch (ch) { + case 'a': /* escape characters */ + return ('\7'); + case 'b': + return ('\b'); + case 'f': + return ('\f'); + case 'n': + return ('\n'); + case 'r': + return ('\r'); + case 't': + return ('\t'); + case 'v': + return ('\13'); + case '\0': /* \" -> \ */ + s->state = EOS; + return ('\\'); + default: /* \x" -> x */ + return (ch); + } +} -- 2.25.1