]> git.cameronkatri.com Git - apple_cmds.git/blob - shell_cmds/echo/echo.c
file_cmds: Fix ipcs
[apple_cmds.git] / shell_cmds / echo / echo.c
1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #if 0
31 #ifndef lint
32 static char const copyright[] =
33 "@(#) Copyright (c) 1989, 1993\n\
34 The Regents of the University of California. All rights reserved.\n";
35 #endif /* not lint */
36
37 #ifndef lint
38 static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93";
39 #endif /* not lint */
40 #endif
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD: src/bin/echo/echo.c,v 1.18 2005/01/10 08:39:22 imp Exp $");
43
44 #include <err.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <wchar.h>
49
50 static void
51 flush_and_exit(void)
52 {
53 if (fflush(stdout) != 0)
54 err(1, "fflush");
55 exit(0);
56 }
57
58 static char *
59 print_one_char(char *cur, int posix, int *bytes_len_out)
60 {
61 char *next;
62 wchar_t wc;
63 int bytes_len = mbtowc(&wc, cur, MB_CUR_MAX);
64 if (bytes_len <= 0) {
65 putchar(*cur);
66 bytes_len = 1;
67 goto out;
68 }
69
70 /* If this is not an escape sequence, just print the character */
71 if (wc != '\\') {
72 putwchar(wc);
73 goto out;
74 }
75
76 next = cur + bytes_len;
77
78 if (!posix) {
79 /* In non-POSIX mode, the only valid escape sequence is \c */
80 if (*next == 'c') {
81 flush_and_exit();
82 } else {
83 putchar(wc);
84 goto out;
85 }
86 } else {
87 cur = next;
88 bytes_len = 1;
89 }
90
91 switch (*cur) {
92 case 'a':
93 putchar('\a');
94 goto out;
95
96 case 'b':
97 putchar('\b');
98 goto out;
99
100 case 'c':
101 flush_and_exit();
102
103 case 'f':
104 putchar('\f');
105 goto out;
106
107 case 'n':
108 putchar('\n');
109 goto out;
110
111 case 'r':
112 putchar('\r');
113 goto out;
114
115 case 't':
116 putchar('\t');
117 goto out;
118
119 case 'v':
120 putchar('\v');
121 goto out;
122
123 case '\\':
124 putchar('\\');
125 goto out;
126
127 case '0': {
128 int j = 0, num = 0;
129 while ((*++cur >= '0' && *cur <= '7') &&
130 j++ < 3) {
131 num <<= 3;
132 num |= (*cur - '0');
133 }
134 putchar(num);
135 --cur;
136 goto out;
137 }
138 default:
139 --cur;
140 putchar(*cur);
141 goto out;
142 }
143
144 out:
145 if (bytes_len_out)
146 *bytes_len_out = bytes_len;
147 return cur;
148 }
149
150 int
151 main(int argc, char *argv[])
152 {
153 int nflag = 0;
154 int posix = (getenv("POSIXLY_CORRECT") != NULL || getenv("POSIX_PEDANTIC") != NULL);
155
156 if (!posix && argv[1] && strcmp(argv[1], "-n") == 0)
157 nflag = 1;
158
159 for (int i = 0; i < argc; i++) {
160 /* argv[0] == progname */
161 int ignore_arg = (i == 0 || (i == 1 && nflag == 1));
162 int last_arg = (i == (argc - 1));
163 if (!ignore_arg) {
164 char *cur = argv[i];
165 size_t arg_len = strlen(cur);
166 int bytes_len = 0;
167
168 for (const char *end = cur + arg_len; cur < end; cur += bytes_len) {
169 cur = print_one_char(cur, posix, &bytes_len);
170 }
171 }
172 if (last_arg && !nflag)
173 putchar('\n');
174 else if (!last_arg && !ignore_arg)
175 putchar(' ');
176
177 if (fflush(stdout) != 0)
178 err(1, "fflush");
179 }
180
181 return 0;
182 }