1139969Simp/*-
21556Srgrimes * Copyright (c) 1989, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * Redistribution and use in source and binary forms, with or without
61556Srgrimes * modification, are permitted provided that the following conditions
71556Srgrimes * are met:
81556Srgrimes * 1. Redistributions of source code must retain the above copyright
91556Srgrimes *    notice, this list of conditions and the following disclaimer.
101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer in the
121556Srgrimes *    documentation and/or other materials provided with the distribution.
131556Srgrimes * 4. Neither the name of the University nor the names of its contributors
141556Srgrimes *    may be used to endorse or promote products derived from this software
151556Srgrimes *    without specific prior written permission.
161556Srgrimes *
171556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271556Srgrimes * SUCH DAMAGE.
281556Srgrimes */
291556Srgrimes
30114433Sobrien#if 0
311556Srgrimes#ifndef lint
3220420Sstevestatic char const copyright[] =
331556Srgrimes"@(#) Copyright (c) 1989, 1993\n\
341556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
351556Srgrimes#endif /* not lint */
361556Srgrimes
371556Srgrimes#ifndef lint
3836009Scharnierstatic char sccsid[] = "@(#)echo.c	8.1 (Berkeley) 5/31/93";
39114433Sobrien#endif /* not lint */
4036009Scharnier#endif
4199109Sobrien#include <sys/cdefs.h>
4299109Sobrien__FBSDID("$FreeBSD$");
431556Srgrimes
44121010Sdds#include <sys/types.h>
45121010Sdds#include <sys/uio.h>
46121010Sdds
47121010Sdds#include <assert.h>
48121010Sdds#include <errno.h>
49121010Sdds#include <limits.h>
50121010Sdds#include <stdlib.h>
51121010Sdds#include <string.h>
52106835Snjl#include <unistd.h>
531556Srgrimes
54121010Sdds/*
55121010Sdds * Report an error and exit.
56121010Sdds * Use it instead of err(3) to avoid linking-in stdio.
57121010Sdds */
58181269Scpercivastatic __dead2 void
59121010Sddserrexit(const char *prog, const char *reason)
60121010Sdds{
61121010Sdds	char *errstr = strerror(errno);
62121010Sdds	write(STDERR_FILENO, prog, strlen(prog));
63121010Sdds	write(STDERR_FILENO, ": ", 2);
64121010Sdds	write(STDERR_FILENO, reason, strlen(reason));
65121010Sdds	write(STDERR_FILENO, ": ", 2);
66121010Sdds	write(STDERR_FILENO, errstr, strlen(errstr));
67121010Sdds	write(STDERR_FILENO, "\n", 1);
68121010Sdds	exit(1);
69121010Sdds}
70121010Sdds
711556Srgrimesint
72121010Sddsmain(int argc, char *argv[])
731556Srgrimes{
7491614Salfred	int nflag;	/* if not set, output a trailing newline. */
75121010Sdds	int veclen;	/* number of writev arguments. */
76121010Sdds	struct iovec *iov, *vp; /* Elements to write, current element. */
77121010Sdds	char space[] = " ";
78121010Sdds	char newline[] = "\n";
79121010Sdds	char *progname = argv[0];
801556Srgrimes
811556Srgrimes	/* This utility may NOT do getopt(3) option parsing. */
821556Srgrimes	if (*++argv && !strcmp(*argv, "-n")) {
831556Srgrimes		++argv;
84121010Sdds		--argc;
851556Srgrimes		nflag = 1;
86121010Sdds	} else
871556Srgrimes		nflag = 0;
881556Srgrimes
89121010Sdds	veclen = (argc >= 2) ? (argc - 2) * 2 + 1 : 0;
90121010Sdds
91121010Sdds	if ((vp = iov = malloc((veclen + 1) * sizeof(struct iovec))) == NULL)
92121010Sdds		errexit(progname, "malloc");
93121010Sdds
9491614Salfred	while (argv[0] != NULL) {
95106835Snjl		size_t len;
96106835Snjl
97106835Snjl		len = strlen(argv[0]);
9810498Sjkh
9991614Salfred		/*
10091614Salfred		 * If the next argument is NULL then this is this
10191614Salfred		 * the last argument, therefore we need to check
10291614Salfred		 * for a trailing \c.
10391614Salfred		 */
10491614Salfred		if (argv[1] == NULL) {
10591614Salfred			/* is there room for a '\c' and is there one? */
10691614Salfred			if (len >= 2 &&
10791614Salfred			    argv[0][len - 2] == '\\' &&
10891614Salfred			    argv[0][len - 1] == 'c') {
10991614Salfred				/* chop it and set the no-newline flag. */
110106835Snjl				len -= 2;
11191614Salfred				nflag = 1;
11291614Salfred			}
11310498Sjkh		}
114121010Sdds		vp->iov_base = *argv;
115121010Sdds		vp++->iov_len = len;
116121010Sdds		if (*++argv) {
117121010Sdds			vp->iov_base = space;
118121010Sdds			vp++->iov_len = 1;
119121010Sdds		}
1201556Srgrimes	}
121121010Sdds	if (!nflag) {
122121010Sdds		veclen++;
123121010Sdds		vp->iov_base = newline;
124121010Sdds		vp++->iov_len = 1;
125121010Sdds	}
126121010Sdds	/* assert(veclen == (vp - iov)); */
127121010Sdds	while (veclen) {
128121010Sdds		int nwrite;
129121010Sdds
130121010Sdds		nwrite = (veclen > IOV_MAX) ? IOV_MAX : veclen;
131121010Sdds		if (writev(STDOUT_FILENO, iov, nwrite) == -1)
132121010Sdds			errexit(progname, "write");
133121010Sdds		iov += nwrite;
134121010Sdds		veclen -= nwrite;
135121010Sdds	}
13691082Smarkm	return 0;
1371556Srgrimes}
138