aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/echo.c
blob: 576cad70c12670b218c6aaffc997b2bec32b897e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/* vi: set sw=4 ts=4:
 *
 * echo.c - echo supporting -n and -e.
 *
 * Copyright 2007 Rob Landley <rob@landley.net>
 *
 * See http://opengroup.org/onlinepubs/9699919799/utilities/echo.html

USE_ECHO(NEWTOY(echo, "^?en", TOYFLAG_BIN))

config ECHO
	bool "echo"
	default y
	help
	  usage: echo [-ne] [args...]

	  Write each argument to stdout, with one space between each, followed
	  by a newline.

	  -n	No trailing newline.
	  -e	Process the following escape sequences:
	   \\	 backslash
	   \0NNN octal values (1 to 3 digits)
	   \a	 alert (beep/flash)
	   \b	 backspace
	   \c	 stop output here (avoids trailing newline)
	   \f	 form feed
	   \n	 newline
	   \r	 carriage return
	   \t	 horizontal tab
	   \v	 vertical tab
	   \xHH	 hexadecimal values (1 to 2 digits)
*/

#define THIS echo
#include "toys.h"

#define FLAG_e (1<<1)
#define FLAG_n (1<<0)

void echo_main(void)
{
	int i = 0, out;
	char *arg, *from = "\\abfnrtv", *to = "\\\a\b\f\n\r\t\v", *c;

	for (;;) {
		arg = toys.optargs[i];
		if (!arg) break;
		if (i++) xputc(' ');

		// Should we output arg verbatim?

		if (!(toys.optflags&FLAG_e)) {
			xprintf("%s", arg);
			continue;
		}

		// Handle -e

		for (c=arg;;) {
			if (!(out = *(c++))) break;

			// handle \escapes
			if (out == '\\' && *c) {
				int n = 0, slash = *(c++);
				char *found = strchr(from, slash);
				if (found) out = to[found-from];
				else if (slash == 'c') goto done;
				else if (slash == '0') {
					out = 0;
					while (*c>='0' && *c<='7' && n++<3)
						out = (out*8)+*(c++)-'0';
				} else if (slash == 'x') {
					out = 0;							
					while (n++<2) {
						if (*c>='0' && *c<='9')
							out = (out*16)+*(c++)-'0';
						else {
							int temp = tolower(*c);
							if (temp>='a' && temp<='f') {
								out = (out*16)+temp-'a'+10;
								c++;
							} else break;
						}
					}
				// Slash in front of unknown character, print literal.
				} else c--;
			}
			xputc(out);
		}
	}

	// Output "\n" if no -n
	if (!(toys.optflags&FLAG_n)) xputc('\n');
done:
	xflush();
}