xref: /freebsd/bin/echo/echo.c (revision 9ddb49cbe45441fa3f3a10f6dd355e9956480b5f)
19ddb49cbSWarner Losh /*-
24b88c807SRodney W. Grimes  * Copyright (c) 1989, 1993
34b88c807SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
44b88c807SRodney W. Grimes  *
54b88c807SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
64b88c807SRodney W. Grimes  * modification, are permitted provided that the following conditions
74b88c807SRodney W. Grimes  * are met:
84b88c807SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
94b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
104b88c807SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
114b88c807SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
124b88c807SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
134b88c807SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
144b88c807SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
154b88c807SRodney W. Grimes  *    without specific prior written permission.
164b88c807SRodney W. Grimes  *
174b88c807SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
184b88c807SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194b88c807SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
204b88c807SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
214b88c807SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
224b88c807SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
234b88c807SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
244b88c807SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
254b88c807SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264b88c807SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274b88c807SRodney W. Grimes  * SUCH DAMAGE.
284b88c807SRodney W. Grimes  */
294b88c807SRodney W. Grimes 
3009a80d48SDavid E. O'Brien #if 0
314b88c807SRodney W. Grimes #ifndef lint
3278b09ffeSSteve Price static char const copyright[] =
334b88c807SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\
344b88c807SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
354b88c807SRodney W. Grimes #endif /* not lint */
364b88c807SRodney W. Grimes 
374b88c807SRodney W. Grimes #ifndef lint
3895d0bf65SPhilippe Charnier static char sccsid[] = "@(#)echo.c	8.1 (Berkeley) 5/31/93";
394b88c807SRodney W. Grimes #endif /* not lint */
4009a80d48SDavid E. O'Brien #endif
415eb43ac2SDavid E. O'Brien #include <sys/cdefs.h>
425eb43ac2SDavid E. O'Brien __FBSDID("$FreeBSD$");
434b88c807SRodney W. Grimes 
4491b7d6dcSDiomidis Spinellis #include <sys/types.h>
4591b7d6dcSDiomidis Spinellis #include <sys/uio.h>
464b88c807SRodney W. Grimes 
4791b7d6dcSDiomidis Spinellis #include <assert.h>
4891b7d6dcSDiomidis Spinellis #include <errno.h>
4991b7d6dcSDiomidis Spinellis #include <limits.h>
5091b7d6dcSDiomidis Spinellis #include <stdlib.h>
5191b7d6dcSDiomidis Spinellis #include <string.h>
5291b7d6dcSDiomidis Spinellis #include <unistd.h>
5391b7d6dcSDiomidis Spinellis 
5491b7d6dcSDiomidis Spinellis /*
5591b7d6dcSDiomidis Spinellis  * Report an error and exit.
5691b7d6dcSDiomidis Spinellis  * Use it instead of err(3) to avoid linking-in stdio.
5791b7d6dcSDiomidis Spinellis  */
5891b7d6dcSDiomidis Spinellis static void
5991b7d6dcSDiomidis Spinellis errexit(const char *prog, const char *reason)
6091b7d6dcSDiomidis Spinellis {
6191b7d6dcSDiomidis Spinellis 	char *errstr = strerror(errno);
6291b7d6dcSDiomidis Spinellis 	write(STDERR_FILENO, prog, strlen(prog));
6391b7d6dcSDiomidis Spinellis 	write(STDERR_FILENO, ": ", 2);
6491b7d6dcSDiomidis Spinellis 	write(STDERR_FILENO, reason, strlen(reason));
6591b7d6dcSDiomidis Spinellis 	write(STDERR_FILENO, ": ", 2);
6691b7d6dcSDiomidis Spinellis 	write(STDERR_FILENO, errstr, strlen(errstr));
6791b7d6dcSDiomidis Spinellis 	write(STDERR_FILENO, "\n", 1);
6891b7d6dcSDiomidis Spinellis 	exit(1);
6991b7d6dcSDiomidis Spinellis }
7091b7d6dcSDiomidis Spinellis 
714b88c807SRodney W. Grimes int
7291b7d6dcSDiomidis Spinellis main(int argc, char *argv[])
734b88c807SRodney W. Grimes {
746188858aSAlfred Perlstein 	int nflag;	/* if not set, output a trailing newline. */
7591b7d6dcSDiomidis Spinellis 	int veclen;	/* number of writev arguments. */
7691b7d6dcSDiomidis Spinellis 	struct iovec *iov, *vp; /* Elements to write, current element. */
7791b7d6dcSDiomidis Spinellis 	char space[] = " ";
7891b7d6dcSDiomidis Spinellis 	char newline[] = "\n";
7991b7d6dcSDiomidis Spinellis 	char *progname = argv[0];
804b88c807SRodney W. Grimes 
814b88c807SRodney W. Grimes 	/* This utility may NOT do getopt(3) option parsing. */
824b88c807SRodney W. Grimes 	if (*++argv && !strcmp(*argv, "-n")) {
834b88c807SRodney W. Grimes 		++argv;
8491b7d6dcSDiomidis Spinellis 		--argc;
854b88c807SRodney W. Grimes 		nflag = 1;
8691b7d6dcSDiomidis Spinellis 	} else
874b88c807SRodney W. Grimes 		nflag = 0;
884b88c807SRodney W. Grimes 
8991b7d6dcSDiomidis Spinellis 	veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0;
9091b7d6dcSDiomidis Spinellis 
9191b7d6dcSDiomidis Spinellis 	if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL)
9291b7d6dcSDiomidis Spinellis 		errexit(progname, "malloc");
9391b7d6dcSDiomidis Spinellis 
946188858aSAlfred Perlstein 	while (argv[0] != NULL) {
95ef3e71daSNate Lawson 		size_t len;
96ef3e71daSNate Lawson 
97ef3e71daSNate Lawson 		len = strlen(argv[0]);
986cef43a7SJordan K. Hubbard 
996188858aSAlfred Perlstein 		/*
1006188858aSAlfred Perlstein 		 * If the next argument is NULL then this is this
1016188858aSAlfred Perlstein 		 * the last argument, therefore we need to check
1026188858aSAlfred Perlstein 		 * for a trailing \c.
1036188858aSAlfred Perlstein 		 */
1046188858aSAlfred Perlstein 		if (argv[1] == NULL) {
1056188858aSAlfred Perlstein 			/* is there room for a '\c' and is there one? */
1066188858aSAlfred Perlstein 			if (len >= 2 &&
1076188858aSAlfred Perlstein 			    argv[0][len - 2] == '\\' &&
1086188858aSAlfred Perlstein 			    argv[0][len - 1] == 'c') {
1096188858aSAlfred Perlstein 				/* chop it and set the no-newline flag. */
110ef3e71daSNate Lawson 				len -= 2;
1116cef43a7SJordan K. Hubbard 				nflag = 1;
1126cef43a7SJordan K. Hubbard 			}
1136188858aSAlfred Perlstein 		}
11491b7d6dcSDiomidis Spinellis 		vp->iov_base = *argv;
11591b7d6dcSDiomidis Spinellis 		vp++->iov_len = len;
11691b7d6dcSDiomidis Spinellis 		if (*++argv) {
11791b7d6dcSDiomidis Spinellis 			vp->iov_base = space;
11891b7d6dcSDiomidis Spinellis 			vp++->iov_len = 1;
1194b88c807SRodney W. Grimes 		}
12091b7d6dcSDiomidis Spinellis 	}
12191b7d6dcSDiomidis Spinellis 	if (!nflag) {
12291b7d6dcSDiomidis Spinellis 		veclen++;
12391b7d6dcSDiomidis Spinellis 		vp->iov_base = newline;
12491b7d6dcSDiomidis Spinellis 		vp++->iov_len = 1;
12591b7d6dcSDiomidis Spinellis 	}
12691b7d6dcSDiomidis Spinellis 	/* assert(veclen == (vp - iov)); */
12791b7d6dcSDiomidis Spinellis 	while (veclen) {
12891b7d6dcSDiomidis Spinellis 		int nwrite;
12991b7d6dcSDiomidis Spinellis 
13091b7d6dcSDiomidis Spinellis 		nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen;
13191b7d6dcSDiomidis Spinellis 		if (writev(STDOUT_FILENO, iov, nwrite) == -1)
13291b7d6dcSDiomidis Spinellis 			errexit(progname, "write");
13391b7d6dcSDiomidis Spinellis 		iov += nwrite;
13491b7d6dcSDiomidis Spinellis 		veclen -= nwrite;
13591b7d6dcSDiomidis Spinellis 	}
1369b2010a2SMark Murray 	return 0;
1374b88c807SRodney W. Grimes }
138