1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /*	  All Rights Reserved  	*/
30 
31 #if defined(sun)
32 #pragma ident	"@(#)echo.c	1.17	05/09/13 SMI"
33 #endif
34 
35 #include "defs.h"
36 
37 /*
38  * Copyright 2008-2019 J. Schilling
39  *
40  * @(#)echo.c	1.19 19/01/08 2008-2019 J. Schilling
41  */
42 #ifndef lint
43 static	UConst char sccsid[] =
44 	"@(#)echo.c	1.19 19/01/08 2008-2019 J. Schilling";
45 #endif
46 
47 /*
48  *	UNIX shell
49  */
50 
51 #define	exit(a)	flushb(); return (a)
52 
53 	int	echo		__PR((int argc, unsigned char **argv));
54 unsigned char	*escape_char	__PR((unsigned char *cp, unsigned char *res,
55 							int echomode));
56 
57 int
echo(argc,argv)58 echo(argc, argv)
59 	int		argc;
60 	unsigned char	**argv;
61 {
62 	unsigned char	*cp;
63 	int	i;
64 	int	nflg = 0;
65 	int	len;
66 	wchar_t	wc;
67 
68 #ifdef	_iBCS2		/* SCO compatibility support */
69 	struct namnod   *sysv3;
70 	int	do_sysv3 = 0;
71 
72 	if ((flags & ppath) == 0) {
73 		sysv3 = findnam((unsigned char *)"SYSV3");
74 		if (sysv3 && (sysv3->namflg & (N_EXPORT | N_ENVNAM)))
75 			do_sysv3 = 1;
76 	}
77 
78 	/* Do the -n parsing if sysv3 is set or if ucb_builtsin is set */
79 	if (ucb_builtins && !do_sysv3 && ((flags & ppath) == 0)) {
80 #else
81 	if (ucb_builtins && ((flags & ppath) == 0)) {
82 #endif /* _iBCS2 */
83 
84 		nflg = 0;
85 		if (argc > 1 && argv[1][0] == '-' &&
86 		    argv[1][1] == 'n' && argv[1][2] == '\0') {
87 			nflg++;
88 			argc--;
89 			argv++;
90 		}
91 
92 		for (i = 1; i < argc; i++) {
93 			sigchk();
94 
95 			for (cp = argv[i]; *cp; cp++) {
96 				prc_buff(*cp);
97 			}
98 
99 			if (i < argc-1)
100 				prc_buff(' ');
101 		}
102 
103 		if (nflg == 0)
104 			prc_buff('\n');
105 		exit(0);
106 	} else {
107 		if (--argc == 0) {
108 			prc_buff('\n');
109 			exit(0);
110 		}
111 #ifdef  _iBCS2
112 		if (do_sysv3) {
113 			if (argc > 1 && argv[1][0] == '-' &&
114 			    argv[1][1] == 'n' && argv[1][2] == '\0') {
115 				nflg++;
116 				/* Step past the -n */
117 				argc--;
118 				argv++;
119 			}
120 		}
121 #endif /* _iBCS2 */
122 
123 		for (i = 1; i <= argc; i++) {
124 			sigchk();
125 			(void) mbtowc(NULL, NULL, 0);
126 			for (cp = argv[i]; *cp; cp++) {
127 				if ((len = mbtowc(&wc, (char *)cp,
128 						MB_LEN_MAX)) <= 0) {
129 					(void) mbtowc(NULL, NULL, 0);
130 					prc_buff(*cp);
131 					continue;
132 				}
133 
134 				if (wc == '\\') {
135 					unsigned char	cc;
136 
137 					cp = escape_char(cp, &cc, TRUE);
138 					if (cp == NULL) {
139 						exit(0);
140 					}
141 					prc_buff(cc);
142 					continue;
143 				} else {
144 					for (; len > 0; len--)
145 						prc_buff(*cp++);
146 					cp--;
147 					continue;
148 				}
149 			}
150 #ifdef	_iBCS2
151 			/* Don't do if don't want newlines & out of args */
152 			if (!(nflg && i == argc))
153 #endif /* _iBCS2 */
154 				prc_buff(i == argc? '\n': ' ');
155 		}
156 		exit(0);
157 	}
158 }
159 
160 unsigned char *
escape_char(cp,res,echomode)161 escape_char(cp, res, echomode)
162 	unsigned char	*cp;
163 	unsigned char	*res;
164 	int		echomode;	/* echo mode vs. C mode */
165 {
166 	int		j;
167 	int		wd;
168 	unsigned char	c;
169 
170 	switch (*++cp) {
171 #if	defined(DO_SYSPRINTF) || defined(DO_ECHO_A)
172 	case 'a':	c = ALERT; break;
173 #endif
174 	case 'b':	c = '\b'; break;
175 	case 'c':	if (echomode)
176 				return (NULL);
177 			goto norm;
178 	case 'f':	c = '\f'; break;
179 	case 'n':	c = '\n'; break;
180 	case 'r':	c = '\r'; break;
181 	case 't':	c = '\t'; break;
182 	case 'v':	c = '\v'; break;
183 	case '\\':	c = '\\'; break;
184 
185 	case '0':
186 		j = wd = 0;
187 		if (!echomode)		/* '\0123' must be '\n3' */
188 			j = 1;
189 	oct:
190 		while ((*++cp >= '0' &&
191 		    *cp <= '7') && j++ < 3) {
192 			wd <<= 3;
193 			wd |= (*cp - '0');
194 		}
195 		c = wd;
196 		--cp;
197 		break;
198 
199 	case '1': case '2': case '3': case '4':
200 	case '5': case '6': case '7':
201 		if (!echomode) {
202 			j = 1;
203 			wd = (*cp - '0');
204 			goto oct;
205 		}
206 		/* FALLTHRU */
207 	default:
208 	norm:
209 		c = *--cp;
210 	}
211 	*res = c;
212 	return (cp);
213 }
214