diff options
author | Erik Andersen <andersen@codepoet.org> | 2000-03-05 08:07:00 +0000 |
---|---|---|
committer | Erik Andersen <andersen@codepoet.org> | 2000-03-05 08:07:00 +0000 |
commit | fb002d0df02ce53e8bcc03fe6e451b250b4d519e (patch) | |
tree | a1237f67ea857f4c83e6f51873177a9d3e5f16f0 | |
parent | 66be5e7e29ad6fa457376996b4c08d307b92a6f1 (diff) | |
download | busybox-w32-fb002d0df02ce53e8bcc03fe6e451b250b4d519e.tar.gz busybox-w32-fb002d0df02ce53e8bcc03fe6e451b250b4d519e.tar.bz2 busybox-w32-fb002d0df02ce53e8bcc03fe6e451b250b4d519e.zip |
Add in tr and dirname
-Erik
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | applets/busybox.c | 6 | ||||
-rw-r--r-- | busybox.c | 6 | ||||
-rw-r--r-- | busybox.def.h | 2 | ||||
-rw-r--r-- | coreutils/dirname.c | 146 | ||||
-rw-r--r-- | coreutils/tr.c | 578 | ||||
-rw-r--r-- | dirname.c | 146 | ||||
-rw-r--r-- | internal.h | 2 | ||||
-rw-r--r-- | tr.c | 578 |
10 files changed, 1468 insertions, 0 deletions
@@ -28,6 +28,9 @@ Dave Cinege <dcinege@psychosis.com> | |||
28 | more(v2), makedevs, dutmp, modularization, auto links file, | 28 | more(v2), makedevs, dutmp, modularization, auto links file, |
29 | various fixes, Linux Router Project maintenance | 29 | various fixes, Linux Router Project maintenance |
30 | 30 | ||
31 | John Lombardo <john@deltanet.com> | ||
32 | dirname, tr | ||
33 | |||
31 | Linus Torvalds <torvalds@transmeta.com> | 34 | Linus Torvalds <torvalds@transmeta.com> |
32 | mkswap, fsck.minix, mkfs.minix | 35 | mkswap, fsck.minix, mkfs.minix |
33 | 36 | ||
@@ -3,6 +3,7 @@ | |||
3 | * Added freeramdisk, which will free up all memory associated | 3 | * Added freeramdisk, which will free up all memory associated |
4 | with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it> | 4 | with a ram disk. Contributed by Emanuele Caratti <wiz@iol.it> |
5 | and then adjusted a bit by me. | 5 | and then adjusted a bit by me. |
6 | * Added tr and dirname from John Lombardo <john@deltanet.com> | ||
6 | * tar wouldn't create directory entries that don't end in '/', | 7 | * tar wouldn't create directory entries that don't end in '/', |
7 | now it does (thanks to Avery Pennarun <apenwarr@worldvisions.ca>) | 8 | now it does (thanks to Avery Pennarun <apenwarr@worldvisions.ca>) |
8 | * Several fixes from Pavel Roskin <pavel_roskin@geocities.com>: | 9 | * Several fixes from Pavel Roskin <pavel_roskin@geocities.com>: |
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[] = { | |||
76 | #ifdef BB_DF //bin | 76 | #ifdef BB_DF //bin |
77 | {"df", df_main}, | 77 | {"df", df_main}, |
78 | #endif | 78 | #endif |
79 | #ifdef BB_DIRNAME //usr/bin | ||
80 | {"dirname", dirname_main}, | ||
81 | #endif | ||
79 | #ifdef BB_DMESG //bin | 82 | #ifdef BB_DMESG //bin |
80 | {"dmesg", dmesg_main}, | 83 | {"dmesg", dmesg_main}, |
81 | #endif | 84 | #endif |
@@ -261,6 +264,9 @@ static const struct Applet applets[] = { | |||
261 | #ifdef BB_TOUCH //usr/bin | 264 | #ifdef BB_TOUCH //usr/bin |
262 | {"touch", touch_main}, | 265 | {"touch", touch_main}, |
263 | #endif | 266 | #endif |
267 | #ifdef BB_TR //usr/bin | ||
268 | {"tr", tr_main}, | ||
269 | #endif | ||
264 | #ifdef BB_TRUE_FALSE //bin | 270 | #ifdef BB_TRUE_FALSE //bin |
265 | {"true", true_main}, | 271 | {"true", true_main}, |
266 | {"false", false_main}, | 272 | {"false", false_main}, |
@@ -76,6 +76,9 @@ static const struct Applet applets[] = { | |||
76 | #ifdef BB_DF //bin | 76 | #ifdef BB_DF //bin |
77 | {"df", df_main}, | 77 | {"df", df_main}, |
78 | #endif | 78 | #endif |
79 | #ifdef BB_DIRNAME //usr/bin | ||
80 | {"dirname", dirname_main}, | ||
81 | #endif | ||
79 | #ifdef BB_DMESG //bin | 82 | #ifdef BB_DMESG //bin |
80 | {"dmesg", dmesg_main}, | 83 | {"dmesg", dmesg_main}, |
81 | #endif | 84 | #endif |
@@ -261,6 +264,9 @@ static const struct Applet applets[] = { | |||
261 | #ifdef BB_TOUCH //usr/bin | 264 | #ifdef BB_TOUCH //usr/bin |
262 | {"touch", touch_main}, | 265 | {"touch", touch_main}, |
263 | #endif | 266 | #endif |
267 | #ifdef BB_TR //usr/bin | ||
268 | {"tr", tr_main}, | ||
269 | #endif | ||
264 | #ifdef BB_TRUE_FALSE //bin | 270 | #ifdef BB_TRUE_FALSE //bin |
265 | {"true", true_main}, | 271 | {"true", true_main}, |
266 | {"false", false_main}, | 272 | {"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 @@ | |||
18 | #define BB_DD | 18 | #define BB_DD |
19 | #define BB_DEALLOCVT | 19 | #define BB_DEALLOCVT |
20 | #define BB_DF | 20 | #define BB_DF |
21 | #define BB_DIRNAME | ||
21 | #define BB_DMESG | 22 | #define BB_DMESG |
22 | //#define BB_DUTMP | 23 | //#define BB_DUTMP |
23 | #define BB_DU | 24 | #define BB_DU |
@@ -84,6 +85,7 @@ | |||
84 | // Don't turn BB_TELNET on. It doesn't work. | 85 | // Don't turn BB_TELNET on. It doesn't work. |
85 | #define BB_TELNET | 86 | #define BB_TELNET |
86 | #define BB_TOUCH | 87 | #define BB_TOUCH |
88 | #define BB_TR | ||
87 | #define BB_TRUE_FALSE | 89 | #define BB_TRUE_FALSE |
88 | #define BB_TTY | 90 | #define BB_TTY |
89 | #define BB_UPTIME | 91 | #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 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * This is temporary -- needs to be rewritten to be tighter */ | ||
4 | /* | ||
5 | * Copyright (c) 1991, 1993, 1994 | ||
6 | * The Regents of the University of California. All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. All advertising materials mentioning features or use of this software | ||
17 | * must display the following acknowledgement: | ||
18 | * This product includes software developed by the University of | ||
19 | * California, Berkeley and its contributors. | ||
20 | * 4. Neither the name of the University nor the names of its contributors | ||
21 | * may be used to endorse or promote products derived from this software | ||
22 | * without specific prior written permission. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
34 | * SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #if 0 | ||
38 | #ifndef lint | ||
39 | static char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ | ||
40 | The Regents of the University of California. All rights reserved.\n"; | ||
41 | #endif /* not lint */ | ||
42 | |||
43 | #ifndef lint | ||
44 | static char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95"; | ||
45 | #endif /* not lint */ | ||
46 | #endif /* #if 0 */ | ||
47 | |||
48 | #include "internal.h" | ||
49 | #include <stdio.h> | ||
50 | #include <stdlib.h> | ||
51 | #include <unistd.h> | ||
52 | |||
53 | void dirname_usage() | ||
54 | { | ||
55 | |||
56 | (void) fprintf(stderr, "usage: dirname path\n"); | ||
57 | exit(1); | ||
58 | } | ||
59 | |||
60 | extern int dirname_main(argc, argv) | ||
61 | int argc; | ||
62 | char **argv; | ||
63 | { | ||
64 | char *p; | ||
65 | int ch; | ||
66 | |||
67 | while ((ch = getopt(argc, argv, "")) != -1) | ||
68 | switch (ch) { | ||
69 | case '?': | ||
70 | default: | ||
71 | dirname_usage(); | ||
72 | } | ||
73 | argc -= optind; | ||
74 | argv += optind; | ||
75 | |||
76 | if (argc != 1) | ||
77 | dirname_usage(); | ||
78 | |||
79 | /* | ||
80 | * (1) If string is //, skip steps (2) through (5). | ||
81 | * (2) If string consists entirely of slash characters, string | ||
82 | * shall be set to a single slash character. In this case, | ||
83 | * skip steps (3) through (8). | ||
84 | */ | ||
85 | for (p = *argv;; ++p) { | ||
86 | if (!*p) { | ||
87 | if (p > *argv) | ||
88 | (void) printf("/\n"); | ||
89 | else | ||
90 | (void) printf(".\n"); | ||
91 | exit(0); | ||
92 | } | ||
93 | if (*p != '/') | ||
94 | break; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * (3) If there are any trailing slash characters in string, they | ||
99 | * shall be removed. | ||
100 | */ | ||
101 | for (; *p; ++p); | ||
102 | while (*--p == '/') | ||
103 | continue; | ||
104 | *++p = '\0'; | ||
105 | |||
106 | /* | ||
107 | * (4) If there are no slash characters remaining in string, | ||
108 | * string shall be set to a single period character. In this | ||
109 | * case skip steps (5) through (8). | ||
110 | * | ||
111 | * (5) If there are any trailing nonslash characters in string, | ||
112 | * they shall be removed. | ||
113 | */ | ||
114 | while (--p >= *argv) | ||
115 | if (*p == '/') | ||
116 | break; | ||
117 | ++p; | ||
118 | if (p == *argv) { | ||
119 | (void) printf(".\n"); | ||
120 | exit(0); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * (6) If the remaining string is //, it is implementation defined | ||
125 | * whether steps (7) and (8) are skipped or processed. | ||
126 | * | ||
127 | * This case has already been handled, as part of steps (1) and (2). | ||
128 | */ | ||
129 | |||
130 | /* | ||
131 | * (7) If there are any trailing slash characters in string, they | ||
132 | * shall be removed. | ||
133 | */ | ||
134 | while (--p >= *argv) | ||
135 | if (*p != '/') | ||
136 | break; | ||
137 | ++p; | ||
138 | |||
139 | /* | ||
140 | * (8) If the remaining string is empty, string shall be set to | ||
141 | * a single slash character. | ||
142 | */ | ||
143 | *p = '\0'; | ||
144 | (void) printf("%s\n", p == *argv ? "/" : *argv); | ||
145 | exit(0); | ||
146 | } | ||
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 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Copyright (c) 1988, 1993 | ||
4 | * The Regents of the University of California. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * 3. All advertising materials mentioning features or use of this software | ||
15 | * must display the following acknowledgement: | ||
16 | * This product includes software developed by the University of | ||
17 | * California, Berkeley and its contributors. | ||
18 | * 4. Neither the name of the University nor the names of its contributors | ||
19 | * may be used to endorse or promote products derived from this software | ||
20 | * without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
32 | * SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #if 0 | ||
36 | #ifndef lint | ||
37 | static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ | ||
38 | The Regents of the University of California. All rights reserved.\n"; | ||
39 | #endif /* not lint */ | ||
40 | |||
41 | #ifndef lint | ||
42 | #if 0 | ||
43 | static char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95"; | ||
44 | #endif | ||
45 | static const char rcsid[] = | ||
46 | |||
47 | "$Id: tr.c,v 1.1 2000/03/05 08:07:00 erik Exp $"; | ||
48 | #endif /* not lint */ | ||
49 | #endif /* #if 0 */ | ||
50 | |||
51 | #include "internal.h" | ||
52 | #include <locale.h> | ||
53 | #include <sys/types.h> | ||
54 | #include <sys/cdefs.h> | ||
55 | #include <sys/types.h> | ||
56 | |||
57 | #include <err.h> | ||
58 | #include <stdio.h> | ||
59 | #include <stdlib.h> | ||
60 | #include <string.h> | ||
61 | #include <unistd.h> | ||
62 | |||
63 | #include <ctype.h> | ||
64 | #include <err.h> | ||
65 | #include <stddef.h> | ||
66 | |||
67 | typedef struct { | ||
68 | enum { STRING1, STRING2 } which; | ||
69 | enum { EOS, INFINITE, NORMAL, RANGE, SEQUENCE, SET } state; | ||
70 | int cnt; /* character count */ | ||
71 | int lastch; /* last character */ | ||
72 | int equiv[2]; /* equivalence set */ | ||
73 | int *set; /* set of characters */ | ||
74 | char *str; /* user's string */ | ||
75 | } STR; | ||
76 | |||
77 | #include <limits.h> | ||
78 | #define NCHARS (UCHAR_MAX + 1) /* Number of possible characters. */ | ||
79 | #define OOBCH (UCHAR_MAX + 1) /* Out of band character value. */ | ||
80 | |||
81 | static int next __P((STR *)); | ||
82 | |||
83 | static int string1[NCHARS] = { | ||
84 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ASCII */ | ||
85 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | ||
86 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | ||
87 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | ||
88 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
89 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | ||
90 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, | ||
91 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, | ||
92 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, | ||
93 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, | ||
94 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, | ||
95 | 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, | ||
96 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, | ||
97 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, | ||
98 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, | ||
99 | 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, | ||
100 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | ||
101 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, | ||
102 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, | ||
103 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, | ||
104 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, | ||
105 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, | ||
106 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, | ||
107 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, | ||
108 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, | ||
109 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, | ||
110 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, | ||
111 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, | ||
112 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, | ||
113 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, | ||
114 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, | ||
115 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, | ||
116 | }, string2[NCHARS]; | ||
117 | |||
118 | STR s1 = { STRING1, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; | ||
119 | STR s2 = { STRING2, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; | ||
120 | |||
121 | static void setup(string, arg, str, cflag) | ||
122 | int *string; | ||
123 | char *arg; | ||
124 | STR *str; | ||
125 | int cflag; | ||
126 | { | ||
127 | register int cnt, *p; | ||
128 | |||
129 | str->str = arg; | ||
130 | bzero(string, NCHARS * sizeof(int)); | ||
131 | |||
132 | while (next(str)) | ||
133 | string[str->lastch] = 1; | ||
134 | if (cflag) | ||
135 | for (p = string, cnt = NCHARS; cnt--; ++p) | ||
136 | *p = !*p; | ||
137 | } | ||
138 | |||
139 | static void tr_usage() | ||
140 | { | ||
141 | (void) fprintf(stderr, "%s\n%s\n%s\n%s\n", | ||
142 | "usage: tr [-csu] string1 string2", | ||
143 | " tr [-cu] -d string1", | ||
144 | " tr [-cu] -s string1", | ||
145 | " tr [-cu] -ds string1 string2"); | ||
146 | exit(1); | ||
147 | } | ||
148 | |||
149 | |||
150 | extern int tr_main(argc, argv) | ||
151 | int argc; | ||
152 | char **argv; | ||
153 | { | ||
154 | register int ch, cnt, lastch, *p; | ||
155 | int cflag, dflag, sflag, isstring2; | ||
156 | |||
157 | (void) setlocale(LC_CTYPE, ""); | ||
158 | |||
159 | cflag = dflag = sflag = 0; | ||
160 | while ((ch = getopt(argc, argv, "cdsu")) != -1) | ||
161 | switch ((char) ch) { | ||
162 | case 'c': | ||
163 | cflag = 1; | ||
164 | break; | ||
165 | case 'd': | ||
166 | dflag = 1; | ||
167 | break; | ||
168 | case 's': | ||
169 | sflag = 1; | ||
170 | break; | ||
171 | case 'u': | ||
172 | setbuf(stdout, (char *) NULL); | ||
173 | break; | ||
174 | case '?': | ||
175 | default: | ||
176 | tr_usage(); | ||
177 | } | ||
178 | argc -= optind; | ||
179 | argv += optind; | ||
180 | |||
181 | switch (argc) { | ||
182 | case 0: | ||
183 | default: | ||
184 | tr_usage(); | ||
185 | /* NOTREACHED */ | ||
186 | case 1: | ||
187 | isstring2 = 0; | ||
188 | break; | ||
189 | case 2: | ||
190 | isstring2 = 1; | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * tr -ds [-c] string1 string2 | ||
196 | * Delete all characters (or complemented characters) in string1. | ||
197 | * Squeeze all characters in string2. | ||
198 | */ | ||
199 | if (dflag && sflag) { | ||
200 | if (!isstring2) | ||
201 | tr_usage(); | ||
202 | |||
203 | setup(string1, argv[0], &s1, cflag); | ||
204 | setup(string2, argv[1], &s2, 0); | ||
205 | |||
206 | for (lastch = OOBCH; (ch = getchar()) != EOF;) | ||
207 | if (!string1[ch] && (!string2[ch] || lastch != ch)) { | ||
208 | lastch = ch; | ||
209 | (void) putchar(ch); | ||
210 | } | ||
211 | exit(0); | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * tr -d [-c] string1 | ||
216 | * Delete all characters (or complemented characters) in string1. | ||
217 | */ | ||
218 | if (dflag) { | ||
219 | if (isstring2) | ||
220 | tr_usage(); | ||
221 | |||
222 | setup(string1, argv[0], &s1, cflag); | ||
223 | |||
224 | while ((ch = getchar()) != EOF) | ||
225 | if (!string1[ch]) | ||
226 | (void) putchar(ch); | ||
227 | exit(0); | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * tr -s [-c] string1 | ||
232 | * Squeeze all characters (or complemented characters) in string1. | ||
233 | */ | ||
234 | if (sflag && !isstring2) { | ||
235 | setup(string1, argv[0], &s1, cflag); | ||
236 | |||
237 | for (lastch = OOBCH; (ch = getchar()) != EOF;) | ||
238 | if (!string1[ch] || lastch != ch) { | ||
239 | lastch = ch; | ||
240 | (void) putchar(ch); | ||
241 | } | ||
242 | exit(0); | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * tr [-cs] string1 string2 | ||
247 | * Replace all characters (or complemented characters) in string1 with | ||
248 | * the character in the same position in string2. If the -s option is | ||
249 | * specified, squeeze all the characters in string2. | ||
250 | */ | ||
251 | if (!isstring2) | ||
252 | tr_usage(); | ||
253 | |||
254 | s1.str = argv[0]; | ||
255 | s2.str = argv[1]; | ||
256 | |||
257 | if (cflag) | ||
258 | for (cnt = NCHARS, p = string1; cnt--;) | ||
259 | *p++ = OOBCH; | ||
260 | |||
261 | if (!next(&s2)) | ||
262 | errx(1, "empty string2"); | ||
263 | |||
264 | /* If string2 runs out of characters, use the last one specified. */ | ||
265 | if (sflag) | ||
266 | while (next(&s1)) { | ||
267 | string1[s1.lastch] = ch = s2.lastch; | ||
268 | string2[ch] = 1; | ||
269 | (void) next(&s2); | ||
270 | } else | ||
271 | while (next(&s1)) { | ||
272 | string1[s1.lastch] = ch = s2.lastch; | ||
273 | (void) next(&s2); | ||
274 | } | ||
275 | |||
276 | if (cflag) | ||
277 | for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt) | ||
278 | *p = *p == OOBCH ? ch : cnt; | ||
279 | |||
280 | if (sflag) | ||
281 | for (lastch = OOBCH; (ch = getchar()) != EOF;) { | ||
282 | ch = string1[ch]; | ||
283 | if (!string2[ch] || lastch != ch) { | ||
284 | lastch = ch; | ||
285 | (void) putchar(ch); | ||
286 | } | ||
287 | } else | ||
288 | while ((ch = getchar()) != EOF) | ||
289 | (void) putchar(string1[ch]); | ||
290 | exit(0); | ||
291 | } | ||
292 | |||
293 | static int backslash __P((STR *)); | ||
294 | static int bracket __P((STR *)); | ||
295 | static int c_class __P((const void *, const void *)); | ||
296 | static void genclass __P((STR *)); | ||
297 | static void genequiv __P((STR *)); | ||
298 | static int genrange __P((STR *)); | ||
299 | static void genseq __P((STR *)); | ||
300 | |||
301 | static int next(s) | ||
302 | register STR *s; | ||
303 | { | ||
304 | register int ch; | ||
305 | |||
306 | switch (s->state) { | ||
307 | case EOS: | ||
308 | return (0); | ||
309 | case INFINITE: | ||
310 | return (1); | ||
311 | case NORMAL: | ||
312 | switch (ch = (u_char) * s->str) { | ||
313 | case '\0': | ||
314 | s->state = EOS; | ||
315 | return (0); | ||
316 | case '\\': | ||
317 | s->lastch = backslash(s); | ||
318 | break; | ||
319 | case '[': | ||
320 | if (bracket(s)) | ||
321 | return (next(s)); | ||
322 | /* FALLTHROUGH */ | ||
323 | default: | ||
324 | ++s->str; | ||
325 | s->lastch = ch; | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | /* We can start a range at any time. */ | ||
330 | if (s->str[0] == '-' && genrange(s)) | ||
331 | return (next(s)); | ||
332 | return (1); | ||
333 | case RANGE: | ||
334 | if (s->cnt-- == 0) { | ||
335 | s->state = NORMAL; | ||
336 | return (next(s)); | ||
337 | } | ||
338 | ++s->lastch; | ||
339 | return (1); | ||
340 | case SEQUENCE: | ||
341 | if (s->cnt-- == 0) { | ||
342 | s->state = NORMAL; | ||
343 | return (next(s)); | ||
344 | } | ||
345 | return (1); | ||
346 | case SET: | ||
347 | if ((s->lastch = s->set[s->cnt++]) == OOBCH) { | ||
348 | s->state = NORMAL; | ||
349 | return (next(s)); | ||
350 | } | ||
351 | return (1); | ||
352 | } | ||
353 | /* NOTREACHED */ | ||
354 | return (0); | ||
355 | } | ||
356 | |||
357 | static int bracket(s) | ||
358 | register STR *s; | ||
359 | { | ||
360 | register char *p; | ||
361 | |||
362 | switch (s->str[1]) { | ||
363 | case ':': /* "[:class:]" */ | ||
364 | if ((p = strstr(s->str + 2, ":]")) == NULL) | ||
365 | return (0); | ||
366 | *p = '\0'; | ||
367 | s->str += 2; | ||
368 | genclass(s); | ||
369 | s->str = p + 2; | ||
370 | return (1); | ||
371 | case '=': /* "[=equiv=]" */ | ||
372 | if ((p = strstr(s->str + 2, "=]")) == NULL) | ||
373 | return (0); | ||
374 | s->str += 2; | ||
375 | genequiv(s); | ||
376 | return (1); | ||
377 | default: /* "[\###*n]" or "[#*n]" */ | ||
378 | if ((p = strpbrk(s->str + 2, "*]")) == NULL) | ||
379 | return (0); | ||
380 | if (p[0] != '*' || index(p, ']') == NULL) | ||
381 | return (0); | ||
382 | s->str += 1; | ||
383 | genseq(s); | ||
384 | return (1); | ||
385 | } | ||
386 | /* NOTREACHED */ | ||
387 | } | ||
388 | |||
389 | typedef struct { | ||
390 | char *name; | ||
391 | int (*func) __P((int)); | ||
392 | int *set; | ||
393 | } CLASS; | ||
394 | |||
395 | static CLASS classes[] = { | ||
396 | #undef isalnum | ||
397 | {"alnum", isalnum,}, | ||
398 | #undef isalpha | ||
399 | {"alpha", isalpha,}, | ||
400 | /*#undef isblank | ||
401 | { "blank", isblank, },*/ | ||
402 | #undef iscntrl | ||
403 | {"cntrl", iscntrl,}, | ||
404 | #undef isdigit | ||
405 | {"digit", isdigit,}, | ||
406 | #undef isgraph | ||
407 | {"graph", isgraph,}, | ||
408 | #undef islower | ||
409 | {"lower", islower,}, | ||
410 | #undef isprint | ||
411 | {"print", isprint,}, | ||
412 | #undef ispunct | ||
413 | {"punct", ispunct,}, | ||
414 | #undef isspace | ||
415 | {"space", isspace,}, | ||
416 | #undef isupper | ||
417 | {"upper", isupper,}, | ||
418 | #undef isxdigit | ||
419 | {"xdigit", isxdigit,}, | ||
420 | }; | ||
421 | |||
422 | static void genclass(s) | ||
423 | STR *s; | ||
424 | { | ||
425 | register int cnt, (*func) __P((int)); | ||
426 | CLASS *cp, tmp; | ||
427 | int *p; | ||
428 | |||
429 | tmp.name = s->str; | ||
430 | if ((cp = (CLASS *) bsearch(&tmp, classes, sizeof(classes) / | ||
431 | sizeof(CLASS), sizeof(CLASS), | ||
432 | c_class)) == NULL) errx(1, | ||
433 | "unknown class %s", | ||
434 | s->str); | ||
435 | |||
436 | if ((cp->set = p = malloc((NCHARS + 1) * sizeof(int))) == NULL) | ||
437 | errx(1, "malloc"); | ||
438 | bzero(p, (NCHARS + 1) * sizeof(int)); | ||
439 | |||
440 | for (cnt = 0, func = cp->func; cnt < NCHARS; ++cnt) | ||
441 | if ((func) (cnt)) | ||
442 | *p++ = cnt; | ||
443 | *p = OOBCH; | ||
444 | |||
445 | s->cnt = 0; | ||
446 | s->state = SET; | ||
447 | s->set = cp->set; | ||
448 | } | ||
449 | |||
450 | static int c_class(a, b) | ||
451 | const void *a, *b; | ||
452 | { | ||
453 | return (strcmp(((CLASS *) a)->name, ((CLASS *) b)->name)); | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * English doesn't have any equivalence classes, so for now | ||
458 | * we just syntax check and grab the character. | ||
459 | */ | ||
460 | static void genequiv(s) | ||
461 | STR *s; | ||
462 | { | ||
463 | if (*s->str == '\\') { | ||
464 | s->equiv[0] = backslash(s); | ||
465 | if (*s->str != '=') | ||
466 | errx(1, "misplaced equivalence equals sign"); | ||
467 | } else { | ||
468 | s->equiv[0] = s->str[0]; | ||
469 | if (s->str[1] != '=') | ||
470 | errx(1, "misplaced equivalence equals sign"); | ||
471 | } | ||
472 | s->str += 2; | ||
473 | s->cnt = 0; | ||
474 | s->state = SET; | ||
475 | s->set = s->equiv; | ||
476 | } | ||
477 | |||
478 | static int genrange(s) | ||
479 | STR *s; | ||
480 | { | ||
481 | int stopval; | ||
482 | char *savestart; | ||
483 | |||
484 | savestart = s->str; | ||
485 | stopval = *++s->str == '\\' ? backslash(s) : (u_char) * s->str++; | ||
486 | if (stopval < (u_char) s->lastch) { | ||
487 | s->str = savestart; | ||
488 | return (0); | ||
489 | } | ||
490 | s->cnt = stopval - s->lastch + 1; | ||
491 | s->state = RANGE; | ||
492 | --s->lastch; | ||
493 | return (1); | ||
494 | } | ||
495 | |||
496 | static void genseq(s) | ||
497 | STR *s; | ||
498 | { | ||
499 | char *ep; | ||
500 | |||
501 | if (s->which == STRING1) | ||
502 | errx(1, "sequences only valid in string2"); | ||
503 | |||
504 | if (*s->str == '\\') | ||
505 | s->lastch = backslash(s); | ||
506 | else | ||
507 | s->lastch = *s->str++; | ||
508 | if (*s->str != '*') | ||
509 | errx(1, "misplaced sequence asterisk"); | ||
510 | |||
511 | switch (*++s->str) { | ||
512 | case '\\': | ||
513 | s->cnt = backslash(s); | ||
514 | break; | ||
515 | case ']': | ||
516 | s->cnt = 0; | ||
517 | ++s->str; | ||
518 | break; | ||
519 | default: | ||
520 | if (isdigit((u_char) * s->str)) { | ||
521 | s->cnt = strtol(s->str, &ep, 0); | ||
522 | if (*ep == ']') { | ||
523 | s->str = ep + 1; | ||
524 | break; | ||
525 | } | ||
526 | } | ||
527 | errx(1, "illegal sequence count"); | ||
528 | /* NOTREACHED */ | ||
529 | } | ||
530 | |||
531 | s->state = s->cnt ? SEQUENCE : INFINITE; | ||
532 | } | ||
533 | |||
534 | /* | ||
535 | * Translate \??? into a character. Up to 3 octal digits, if no digits either | ||
536 | * an escape code or a literal character. | ||
537 | */ | ||
538 | static int backslash(s) | ||
539 | register STR *s; | ||
540 | { | ||
541 | register int ch, cnt, val; | ||
542 | |||
543 | for (cnt = val = 0;;) { | ||
544 | ch = (u_char) * ++s->str; | ||
545 | if (!isascii(ch) || !isdigit(ch)) | ||
546 | break; | ||
547 | val = val * 8 + ch - '0'; | ||
548 | if (++cnt == 3) { | ||
549 | ++s->str; | ||
550 | break; | ||
551 | } | ||
552 | } | ||
553 | if (cnt) | ||
554 | return (val); | ||
555 | if (ch != '\0') | ||
556 | ++s->str; | ||
557 | switch (ch) { | ||
558 | case 'a': /* escape characters */ | ||
559 | return ('\7'); | ||
560 | case 'b': | ||
561 | return ('\b'); | ||
562 | case 'f': | ||
563 | return ('\f'); | ||
564 | case 'n': | ||
565 | return ('\n'); | ||
566 | case 'r': | ||
567 | return ('\r'); | ||
568 | case 't': | ||
569 | return ('\t'); | ||
570 | case 'v': | ||
571 | return ('\13'); | ||
572 | case '\0': /* \" -> \ */ | ||
573 | s->state = EOS; | ||
574 | return ('\\'); | ||
575 | default: /* \x" -> x */ | ||
576 | return (ch); | ||
577 | } | ||
578 | } | ||
diff --git a/dirname.c b/dirname.c new file mode 100644 index 000000000..77cb664ac --- /dev/null +++ b/dirname.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * This is temporary -- needs to be rewritten to be tighter */ | ||
4 | /* | ||
5 | * Copyright (c) 1991, 1993, 1994 | ||
6 | * The Regents of the University of California. All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer. | ||
13 | * 2. Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * 3. All advertising materials mentioning features or use of this software | ||
17 | * must display the following acknowledgement: | ||
18 | * This product includes software developed by the University of | ||
19 | * California, Berkeley and its contributors. | ||
20 | * 4. Neither the name of the University nor the names of its contributors | ||
21 | * may be used to endorse or promote products derived from this software | ||
22 | * without specific prior written permission. | ||
23 | * | ||
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
34 | * SUCH DAMAGE. | ||
35 | */ | ||
36 | |||
37 | #if 0 | ||
38 | #ifndef lint | ||
39 | static char copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ | ||
40 | The Regents of the University of California. All rights reserved.\n"; | ||
41 | #endif /* not lint */ | ||
42 | |||
43 | #ifndef lint | ||
44 | static char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95"; | ||
45 | #endif /* not lint */ | ||
46 | #endif /* #if 0 */ | ||
47 | |||
48 | #include "internal.h" | ||
49 | #include <stdio.h> | ||
50 | #include <stdlib.h> | ||
51 | #include <unistd.h> | ||
52 | |||
53 | void dirname_usage() | ||
54 | { | ||
55 | |||
56 | (void) fprintf(stderr, "usage: dirname path\n"); | ||
57 | exit(1); | ||
58 | } | ||
59 | |||
60 | extern int dirname_main(argc, argv) | ||
61 | int argc; | ||
62 | char **argv; | ||
63 | { | ||
64 | char *p; | ||
65 | int ch; | ||
66 | |||
67 | while ((ch = getopt(argc, argv, "")) != -1) | ||
68 | switch (ch) { | ||
69 | case '?': | ||
70 | default: | ||
71 | dirname_usage(); | ||
72 | } | ||
73 | argc -= optind; | ||
74 | argv += optind; | ||
75 | |||
76 | if (argc != 1) | ||
77 | dirname_usage(); | ||
78 | |||
79 | /* | ||
80 | * (1) If string is //, skip steps (2) through (5). | ||
81 | * (2) If string consists entirely of slash characters, string | ||
82 | * shall be set to a single slash character. In this case, | ||
83 | * skip steps (3) through (8). | ||
84 | */ | ||
85 | for (p = *argv;; ++p) { | ||
86 | if (!*p) { | ||
87 | if (p > *argv) | ||
88 | (void) printf("/\n"); | ||
89 | else | ||
90 | (void) printf(".\n"); | ||
91 | exit(0); | ||
92 | } | ||
93 | if (*p != '/') | ||
94 | break; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * (3) If there are any trailing slash characters in string, they | ||
99 | * shall be removed. | ||
100 | */ | ||
101 | for (; *p; ++p); | ||
102 | while (*--p == '/') | ||
103 | continue; | ||
104 | *++p = '\0'; | ||
105 | |||
106 | /* | ||
107 | * (4) If there are no slash characters remaining in string, | ||
108 | * string shall be set to a single period character. In this | ||
109 | * case skip steps (5) through (8). | ||
110 | * | ||
111 | * (5) If there are any trailing nonslash characters in string, | ||
112 | * they shall be removed. | ||
113 | */ | ||
114 | while (--p >= *argv) | ||
115 | if (*p == '/') | ||
116 | break; | ||
117 | ++p; | ||
118 | if (p == *argv) { | ||
119 | (void) printf(".\n"); | ||
120 | exit(0); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * (6) If the remaining string is //, it is implementation defined | ||
125 | * whether steps (7) and (8) are skipped or processed. | ||
126 | * | ||
127 | * This case has already been handled, as part of steps (1) and (2). | ||
128 | */ | ||
129 | |||
130 | /* | ||
131 | * (7) If there are any trailing slash characters in string, they | ||
132 | * shall be removed. | ||
133 | */ | ||
134 | while (--p >= *argv) | ||
135 | if (*p != '/') | ||
136 | break; | ||
137 | ++p; | ||
138 | |||
139 | /* | ||
140 | * (8) If the remaining string is empty, string shall be set to | ||
141 | * a single slash character. | ||
142 | */ | ||
143 | *p = '\0'; | ||
144 | (void) printf("%s\n", p == *argv ? "/" : *argv); | ||
145 | exit(0); | ||
146 | } | ||
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); | |||
68 | extern int clear_main(int argc, char** argv); | 68 | extern int clear_main(int argc, char** argv); |
69 | extern int date_main(int argc, char** argv); | 69 | extern int date_main(int argc, char** argv); |
70 | extern int dd_main(int argc, char** argv); | 70 | extern int dd_main(int argc, char** argv); |
71 | extern int dirname_main(int argc, char** argv); | ||
71 | extern int deallocvt_main(int argc, char** argv); | 72 | extern int deallocvt_main(int argc, char** argv); |
72 | extern int df_main(int argc, char** argv); | 73 | extern int df_main(int argc, char** argv); |
73 | extern int dmesg_main(int argc, char** argv); | 74 | extern int dmesg_main(int argc, char** argv); |
@@ -134,6 +135,7 @@ extern int tar_main(int argc, char** argv); | |||
134 | extern int tee_main(int argc, char** argv); | 135 | extern int tee_main(int argc, char** argv); |
135 | extern int telnet_main(int argc, char** argv); | 136 | extern int telnet_main(int argc, char** argv); |
136 | extern int touch_main(int argc, char** argv); | 137 | extern int touch_main(int argc, char** argv); |
138 | extern int tr_main(int argc, char** argv); | ||
137 | extern int true_main(int argc, char** argv); | 139 | extern int true_main(int argc, char** argv); |
138 | extern int tput_main(int argc, char** argv); | 140 | extern int tput_main(int argc, char** argv); |
139 | extern int tryopen_main(int argc, char** argv); | 141 | extern int tryopen_main(int argc, char** argv); |
@@ -0,0 +1,578 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Copyright (c) 1988, 1993 | ||
4 | * The Regents of the University of California. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * 3. All advertising materials mentioning features or use of this software | ||
15 | * must display the following acknowledgement: | ||
16 | * This product includes software developed by the University of | ||
17 | * California, Berkeley and its contributors. | ||
18 | * 4. Neither the name of the University nor the names of its contributors | ||
19 | * may be used to endorse or promote products derived from this software | ||
20 | * without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
32 | * SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #if 0 | ||
36 | #ifndef lint | ||
37 | static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ | ||
38 | The Regents of the University of California. All rights reserved.\n"; | ||
39 | #endif /* not lint */ | ||
40 | |||
41 | #ifndef lint | ||
42 | #if 0 | ||
43 | static char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95"; | ||
44 | #endif | ||
45 | static const char rcsid[] = | ||
46 | |||
47 | "$Id: tr.c,v 1.1 2000/03/05 08:07:00 erik Exp $"; | ||
48 | #endif /* not lint */ | ||
49 | #endif /* #if 0 */ | ||
50 | |||
51 | #include "internal.h" | ||
52 | #include <locale.h> | ||
53 | #include <sys/types.h> | ||
54 | #include <sys/cdefs.h> | ||
55 | #include <sys/types.h> | ||
56 | |||
57 | #include <err.h> | ||
58 | #include <stdio.h> | ||
59 | #include <stdlib.h> | ||
60 | #include <string.h> | ||
61 | #include <unistd.h> | ||
62 | |||
63 | #include <ctype.h> | ||
64 | #include <err.h> | ||
65 | #include <stddef.h> | ||
66 | |||
67 | typedef struct { | ||
68 | enum { STRING1, STRING2 } which; | ||
69 | enum { EOS, INFINITE, NORMAL, RANGE, SEQUENCE, SET } state; | ||
70 | int cnt; /* character count */ | ||
71 | int lastch; /* last character */ | ||
72 | int equiv[2]; /* equivalence set */ | ||
73 | int *set; /* set of characters */ | ||
74 | char *str; /* user's string */ | ||
75 | } STR; | ||
76 | |||
77 | #include <limits.h> | ||
78 | #define NCHARS (UCHAR_MAX + 1) /* Number of possible characters. */ | ||
79 | #define OOBCH (UCHAR_MAX + 1) /* Out of band character value. */ | ||
80 | |||
81 | static int next __P((STR *)); | ||
82 | |||
83 | static int string1[NCHARS] = { | ||
84 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ASCII */ | ||
85 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | ||
86 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, | ||
87 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, | ||
88 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
89 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, | ||
90 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, | ||
91 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, | ||
92 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, | ||
93 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, | ||
94 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, | ||
95 | 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, | ||
96 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, | ||
97 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, | ||
98 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, | ||
99 | 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, | ||
100 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | ||
101 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, | ||
102 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, | ||
103 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, | ||
104 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, | ||
105 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, | ||
106 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, | ||
107 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, | ||
108 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, | ||
109 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, | ||
110 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, | ||
111 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, | ||
112 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, | ||
113 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, | ||
114 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, | ||
115 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, | ||
116 | }, string2[NCHARS]; | ||
117 | |||
118 | STR s1 = { STRING1, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; | ||
119 | STR s2 = { STRING2, NORMAL, 0, OOBCH, {0, OOBCH}, NULL, NULL }; | ||
120 | |||
121 | static void setup(string, arg, str, cflag) | ||
122 | int *string; | ||
123 | char *arg; | ||
124 | STR *str; | ||
125 | int cflag; | ||
126 | { | ||
127 | register int cnt, *p; | ||
128 | |||
129 | str->str = arg; | ||
130 | bzero(string, NCHARS * sizeof(int)); | ||
131 | |||
132 | while (next(str)) | ||
133 | string[str->lastch] = 1; | ||
134 | if (cflag) | ||
135 | for (p = string, cnt = NCHARS; cnt--; ++p) | ||
136 | *p = !*p; | ||
137 | } | ||
138 | |||
139 | static void tr_usage() | ||
140 | { | ||
141 | (void) fprintf(stderr, "%s\n%s\n%s\n%s\n", | ||
142 | "usage: tr [-csu] string1 string2", | ||
143 | " tr [-cu] -d string1", | ||
144 | " tr [-cu] -s string1", | ||
145 | " tr [-cu] -ds string1 string2"); | ||
146 | exit(1); | ||
147 | } | ||
148 | |||
149 | |||
150 | extern int tr_main(argc, argv) | ||
151 | int argc; | ||
152 | char **argv; | ||
153 | { | ||
154 | register int ch, cnt, lastch, *p; | ||
155 | int cflag, dflag, sflag, isstring2; | ||
156 | |||
157 | (void) setlocale(LC_CTYPE, ""); | ||
158 | |||
159 | cflag = dflag = sflag = 0; | ||
160 | while ((ch = getopt(argc, argv, "cdsu")) != -1) | ||
161 | switch ((char) ch) { | ||
162 | case 'c': | ||
163 | cflag = 1; | ||
164 | break; | ||
165 | case 'd': | ||
166 | dflag = 1; | ||
167 | break; | ||
168 | case 's': | ||
169 | sflag = 1; | ||
170 | break; | ||
171 | case 'u': | ||
172 | setbuf(stdout, (char *) NULL); | ||
173 | break; | ||
174 | case '?': | ||
175 | default: | ||
176 | tr_usage(); | ||
177 | } | ||
178 | argc -= optind; | ||
179 | argv += optind; | ||
180 | |||
181 | switch (argc) { | ||
182 | case 0: | ||
183 | default: | ||
184 | tr_usage(); | ||
185 | /* NOTREACHED */ | ||
186 | case 1: | ||
187 | isstring2 = 0; | ||
188 | break; | ||
189 | case 2: | ||
190 | isstring2 = 1; | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * tr -ds [-c] string1 string2 | ||
196 | * Delete all characters (or complemented characters) in string1. | ||
197 | * Squeeze all characters in string2. | ||
198 | */ | ||
199 | if (dflag && sflag) { | ||
200 | if (!isstring2) | ||
201 | tr_usage(); | ||
202 | |||
203 | setup(string1, argv[0], &s1, cflag); | ||
204 | setup(string2, argv[1], &s2, 0); | ||
205 | |||
206 | for (lastch = OOBCH; (ch = getchar()) != EOF;) | ||
207 | if (!string1[ch] && (!string2[ch] || lastch != ch)) { | ||
208 | lastch = ch; | ||
209 | (void) putchar(ch); | ||
210 | } | ||
211 | exit(0); | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * tr -d [-c] string1 | ||
216 | * Delete all characters (or complemented characters) in string1. | ||
217 | */ | ||
218 | if (dflag) { | ||
219 | if (isstring2) | ||
220 | tr_usage(); | ||
221 | |||
222 | setup(string1, argv[0], &s1, cflag); | ||
223 | |||
224 | while ((ch = getchar()) != EOF) | ||
225 | if (!string1[ch]) | ||
226 | (void) putchar(ch); | ||
227 | exit(0); | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * tr -s [-c] string1 | ||
232 | * Squeeze all characters (or complemented characters) in string1. | ||
233 | */ | ||
234 | if (sflag && !isstring2) { | ||
235 | setup(string1, argv[0], &s1, cflag); | ||
236 | |||
237 | for (lastch = OOBCH; (ch = getchar()) != EOF;) | ||
238 | if (!string1[ch] || lastch != ch) { | ||
239 | lastch = ch; | ||
240 | (void) putchar(ch); | ||
241 | } | ||
242 | exit(0); | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * tr [-cs] string1 string2 | ||
247 | * Replace all characters (or complemented characters) in string1 with | ||
248 | * the character in the same position in string2. If the -s option is | ||
249 | * specified, squeeze all the characters in string2. | ||
250 | */ | ||
251 | if (!isstring2) | ||
252 | tr_usage(); | ||
253 | |||
254 | s1.str = argv[0]; | ||
255 | s2.str = argv[1]; | ||
256 | |||
257 | if (cflag) | ||
258 | for (cnt = NCHARS, p = string1; cnt--;) | ||
259 | *p++ = OOBCH; | ||
260 | |||
261 | if (!next(&s2)) | ||
262 | errx(1, "empty string2"); | ||
263 | |||
264 | /* If string2 runs out of characters, use the last one specified. */ | ||
265 | if (sflag) | ||
266 | while (next(&s1)) { | ||
267 | string1[s1.lastch] = ch = s2.lastch; | ||
268 | string2[ch] = 1; | ||
269 | (void) next(&s2); | ||
270 | } else | ||
271 | while (next(&s1)) { | ||
272 | string1[s1.lastch] = ch = s2.lastch; | ||
273 | (void) next(&s2); | ||
274 | } | ||
275 | |||
276 | if (cflag) | ||
277 | for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt) | ||
278 | *p = *p == OOBCH ? ch : cnt; | ||
279 | |||
280 | if (sflag) | ||
281 | for (lastch = OOBCH; (ch = getchar()) != EOF;) { | ||
282 | ch = string1[ch]; | ||
283 | if (!string2[ch] || lastch != ch) { | ||
284 | lastch = ch; | ||
285 | (void) putchar(ch); | ||
286 | } | ||
287 | } else | ||
288 | while ((ch = getchar()) != EOF) | ||
289 | (void) putchar(string1[ch]); | ||
290 | exit(0); | ||
291 | } | ||
292 | |||
293 | static int backslash __P((STR *)); | ||
294 | static int bracket __P((STR *)); | ||
295 | static int c_class __P((const void *, const void *)); | ||
296 | static void genclass __P((STR *)); | ||
297 | static void genequiv __P((STR *)); | ||
298 | static int genrange __P((STR *)); | ||
299 | static void genseq __P((STR *)); | ||
300 | |||
301 | static int next(s) | ||
302 | register STR *s; | ||
303 | { | ||
304 | register int ch; | ||
305 | |||
306 | switch (s->state) { | ||
307 | case EOS: | ||
308 | return (0); | ||
309 | case INFINITE: | ||
310 | return (1); | ||
311 | case NORMAL: | ||
312 | switch (ch = (u_char) * s->str) { | ||
313 | case '\0': | ||
314 | s->state = EOS; | ||
315 | return (0); | ||
316 | case '\\': | ||
317 | s->lastch = backslash(s); | ||
318 | break; | ||
319 | case '[': | ||
320 | if (bracket(s)) | ||
321 | return (next(s)); | ||
322 | /* FALLTHROUGH */ | ||
323 | default: | ||
324 | ++s->str; | ||
325 | s->lastch = ch; | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | /* We can start a range at any time. */ | ||
330 | if (s->str[0] == '-' && genrange(s)) | ||
331 | return (next(s)); | ||
332 | return (1); | ||
333 | case RANGE: | ||
334 | if (s->cnt-- == 0) { | ||
335 | s->state = NORMAL; | ||
336 | return (next(s)); | ||
337 | } | ||
338 | ++s->lastch; | ||
339 | return (1); | ||
340 | case SEQUENCE: | ||
341 | if (s->cnt-- == 0) { | ||
342 | s->state = NORMAL; | ||
343 | return (next(s)); | ||
344 | } | ||
345 | return (1); | ||
346 | case SET: | ||
347 | if ((s->lastch = s->set[s->cnt++]) == OOBCH) { | ||
348 | s->state = NORMAL; | ||
349 | return (next(s)); | ||
350 | } | ||
351 | return (1); | ||
352 | } | ||
353 | /* NOTREACHED */ | ||
354 | return (0); | ||
355 | } | ||
356 | |||
357 | static int bracket(s) | ||
358 | register STR *s; | ||
359 | { | ||
360 | register char *p; | ||
361 | |||
362 | switch (s->str[1]) { | ||
363 | case ':': /* "[:class:]" */ | ||
364 | if ((p = strstr(s->str + 2, ":]")) == NULL) | ||
365 | return (0); | ||
366 | *p = '\0'; | ||
367 | s->str += 2; | ||
368 | genclass(s); | ||
369 | s->str = p + 2; | ||
370 | return (1); | ||
371 | case '=': /* "[=equiv=]" */ | ||
372 | if ((p = strstr(s->str + 2, "=]")) == NULL) | ||
373 | return (0); | ||
374 | s->str += 2; | ||
375 | genequiv(s); | ||
376 | return (1); | ||
377 | default: /* "[\###*n]" or "[#*n]" */ | ||
378 | if ((p = strpbrk(s->str + 2, "*]")) == NULL) | ||
379 | return (0); | ||
380 | if (p[0] != '*' || index(p, ']') == NULL) | ||
381 | return (0); | ||
382 | s->str += 1; | ||
383 | genseq(s); | ||
384 | return (1); | ||
385 | } | ||
386 | /* NOTREACHED */ | ||
387 | } | ||
388 | |||
389 | typedef struct { | ||
390 | char *name; | ||
391 | int (*func) __P((int)); | ||
392 | int *set; | ||
393 | } CLASS; | ||
394 | |||
395 | static CLASS classes[] = { | ||
396 | #undef isalnum | ||
397 | {"alnum", isalnum,}, | ||
398 | #undef isalpha | ||
399 | {"alpha", isalpha,}, | ||
400 | /*#undef isblank | ||
401 | { "blank", isblank, },*/ | ||
402 | #undef iscntrl | ||
403 | {"cntrl", iscntrl,}, | ||
404 | #undef isdigit | ||
405 | {"digit", isdigit,}, | ||
406 | #undef isgraph | ||
407 | {"graph", isgraph,}, | ||
408 | #undef islower | ||
409 | {"lower", islower,}, | ||
410 | #undef isprint | ||
411 | {"print", isprint,}, | ||
412 | #undef ispunct | ||
413 | {"punct", ispunct,}, | ||
414 | #undef isspace | ||
415 | {"space", isspace,}, | ||
416 | #undef isupper | ||
417 | {"upper", isupper,}, | ||
418 | #undef isxdigit | ||
419 | {"xdigit", isxdigit,}, | ||
420 | }; | ||
421 | |||
422 | static void genclass(s) | ||
423 | STR *s; | ||
424 | { | ||
425 | register int cnt, (*func) __P((int)); | ||
426 | CLASS *cp, tmp; | ||
427 | int *p; | ||
428 | |||
429 | tmp.name = s->str; | ||
430 | if ((cp = (CLASS *) bsearch(&tmp, classes, sizeof(classes) / | ||
431 | sizeof(CLASS), sizeof(CLASS), | ||
432 | c_class)) == NULL) errx(1, | ||
433 | "unknown class %s", | ||
434 | s->str); | ||
435 | |||
436 | if ((cp->set = p = malloc((NCHARS + 1) * sizeof(int))) == NULL) | ||
437 | errx(1, "malloc"); | ||
438 | bzero(p, (NCHARS + 1) * sizeof(int)); | ||
439 | |||
440 | for (cnt = 0, func = cp->func; cnt < NCHARS; ++cnt) | ||
441 | if ((func) (cnt)) | ||
442 | *p++ = cnt; | ||
443 | *p = OOBCH; | ||
444 | |||
445 | s->cnt = 0; | ||
446 | s->state = SET; | ||
447 | s->set = cp->set; | ||
448 | } | ||
449 | |||
450 | static int c_class(a, b) | ||
451 | const void *a, *b; | ||
452 | { | ||
453 | return (strcmp(((CLASS *) a)->name, ((CLASS *) b)->name)); | ||
454 | } | ||
455 | |||
456 | /* | ||
457 | * English doesn't have any equivalence classes, so for now | ||
458 | * we just syntax check and grab the character. | ||
459 | */ | ||
460 | static void genequiv(s) | ||
461 | STR *s; | ||
462 | { | ||
463 | if (*s->str == '\\') { | ||
464 | s->equiv[0] = backslash(s); | ||
465 | if (*s->str != '=') | ||
466 | errx(1, "misplaced equivalence equals sign"); | ||
467 | } else { | ||
468 | s->equiv[0] = s->str[0]; | ||
469 | if (s->str[1] != '=') | ||
470 | errx(1, "misplaced equivalence equals sign"); | ||
471 | } | ||
472 | s->str += 2; | ||
473 | s->cnt = 0; | ||
474 | s->state = SET; | ||
475 | s->set = s->equiv; | ||
476 | } | ||
477 | |||
478 | static int genrange(s) | ||
479 | STR *s; | ||
480 | { | ||
481 | int stopval; | ||
482 | char *savestart; | ||
483 | |||
484 | savestart = s->str; | ||
485 | stopval = *++s->str == '\\' ? backslash(s) : (u_char) * s->str++; | ||
486 | if (stopval < (u_char) s->lastch) { | ||
487 | s->str = savestart; | ||
488 | return (0); | ||
489 | } | ||
490 | s->cnt = stopval - s->lastch + 1; | ||
491 | s->state = RANGE; | ||
492 | --s->lastch; | ||
493 | return (1); | ||
494 | } | ||
495 | |||
496 | static void genseq(s) | ||
497 | STR *s; | ||
498 | { | ||
499 | char *ep; | ||
500 | |||
501 | if (s->which == STRING1) | ||
502 | errx(1, "sequences only valid in string2"); | ||
503 | |||
504 | if (*s->str == '\\') | ||
505 | s->lastch = backslash(s); | ||
506 | else | ||
507 | s->lastch = *s->str++; | ||
508 | if (*s->str != '*') | ||
509 | errx(1, "misplaced sequence asterisk"); | ||
510 | |||
511 | switch (*++s->str) { | ||
512 | case '\\': | ||
513 | s->cnt = backslash(s); | ||
514 | break; | ||
515 | case ']': | ||
516 | s->cnt = 0; | ||
517 | ++s->str; | ||
518 | break; | ||
519 | default: | ||
520 | if (isdigit((u_char) * s->str)) { | ||
521 | s->cnt = strtol(s->str, &ep, 0); | ||
522 | if (*ep == ']') { | ||
523 | s->str = ep + 1; | ||
524 | break; | ||
525 | } | ||
526 | } | ||
527 | errx(1, "illegal sequence count"); | ||
528 | /* NOTREACHED */ | ||
529 | } | ||
530 | |||
531 | s->state = s->cnt ? SEQUENCE : INFINITE; | ||
532 | } | ||
533 | |||
534 | /* | ||
535 | * Translate \??? into a character. Up to 3 octal digits, if no digits either | ||
536 | * an escape code or a literal character. | ||
537 | */ | ||
538 | static int backslash(s) | ||
539 | register STR *s; | ||
540 | { | ||
541 | register int ch, cnt, val; | ||
542 | |||
543 | for (cnt = val = 0;;) { | ||
544 | ch = (u_char) * ++s->str; | ||
545 | if (!isascii(ch) || !isdigit(ch)) | ||
546 | break; | ||
547 | val = val * 8 + ch - '0'; | ||
548 | if (++cnt == 3) { | ||
549 | ++s->str; | ||
550 | break; | ||
551 | } | ||
552 | } | ||
553 | if (cnt) | ||
554 | return (val); | ||
555 | if (ch != '\0') | ||
556 | ++s->str; | ||
557 | switch (ch) { | ||
558 | case 'a': /* escape characters */ | ||
559 | return ('\7'); | ||
560 | case 'b': | ||
561 | return ('\b'); | ||
562 | case 'f': | ||
563 | return ('\f'); | ||
564 | case 'n': | ||
565 | return ('\n'); | ||
566 | case 'r': | ||
567 | return ('\r'); | ||
568 | case 't': | ||
569 | return ('\t'); | ||
570 | case 'v': | ||
571 | return ('\13'); | ||
572 | case '\0': /* \" -> \ */ | ||
573 | s->state = EOS; | ||
574 | return ('\\'); | ||
575 | default: /* \x" -> x */ | ||
576 | return (ch); | ||
577 | } | ||
578 | } | ||