1/*
2 * Copyright (C) 1984-2019  Mark Nudelman
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
6 *
7 * For more information, see the README file.
8 */
9
10
11/*
12 * lessecho [-ox] [-cx] [-pn] [-dn] [-a] file ...
13 * Simply echos its filename arguments on standard output.
14 * But any argument containing spaces is enclosed in quotes.
15 *
16 * -ox	Specifies "x" to be the open quote character.
17 * -cx	Specifies "x" to be the close quote character.
18 * -pn	Specifies "n" to be the open quote character, as an integer.
19 * -dn	Specifies "n" to be the close quote character, as an integer.
20 * -mx  Specifies "x" to be a metachar.
21 * -nn  Specifies "n" to be a metachar, as an integer.
22 * -ex  Specifies "x" to be the escape char for metachars.
23 * -fn  Specifies "x" to be the escape char for metachars, as an integer.
24 * -a	Specifies that all arguments are to be quoted.
25 *	The default is that only arguments containing spaces are quoted.
26 */
27
28#include "less.h"
29
30static char *version = "$Revision: 1.15 $";
31
32static int quote_all = 0;
33static char openquote = '"';
34static char closequote = '"';
35static char *meta_escape = "\\";
36static char meta_escape_buf[2];
37static char metachars[64] = "";
38static int num_metachars = 0;
39
40	static void
41pr_usage(VOID_PARAM)
42{
43	fprintf(stderr,
44		"usage: lessecho [-ox] [-cx] [-pn] [-dn] [-mx] [-nn] [-ex] [-fn] [-a] file ...\n");
45}
46
47	static void
48pr_version(VOID_PARAM)
49{
50	char *p;
51	char buf[10];
52	char *pbuf = buf;
53
54	for (p = version;  *p != ' ';  p++)
55		if (*p == '\0')
56			return;
57	for (p++;  *p != '$' && *p != ' ' && *p != '\0';  p++)
58		*pbuf++ = *p;
59	*pbuf = '\0';
60	printf("%s\n", buf);
61}
62
63	static void
64pr_error(s)
65	char *s;
66{
67	fprintf(stderr, "%s\n", s);
68	exit(1);
69}
70
71	static long
72lstrtol(s, radix, pend)
73	char *s;
74	int radix;
75	char **pend;
76{
77	int v;
78	int neg = 0;
79	long n = 0;
80
81	/* Skip leading white space. */
82	while (*s == ' ' || *s == '\t')
83		s++;
84
85	/* Check for a leading + or -. */
86	if (*s == '-')
87	{
88		neg = 1;
89		s++;
90	} else if (*s == '+')
91	{
92		s++;
93	}
94
95	/* Determine radix if caller does not specify. */
96	if (radix == 0)
97	{
98		radix = 10;
99		if (*s == '0')
100		{
101			switch (*++s)
102			{
103			case 'x':
104				radix = 16;
105				s++;
106				break;
107			default:
108				radix = 8;
109				break;
110			}
111		}
112	}
113
114	/* Parse the digits of the number. */
115	for (;;)
116	{
117		if (*s >= '0' && *s <= '9')
118			v = *s - '0';
119		else if (*s >= 'a' && *s <= 'f')
120			v = *s - 'a' + 10;
121		else if (*s >= 'A' && *s <= 'F')
122			v = *s - 'A' + 10;
123		else
124			break;
125		if (v >= radix)
126			break;
127		n = n * radix + v;
128		s++;
129	}
130
131	if (pend != NULL)
132	{
133		/* Skip trailing white space. */
134		while (*s == ' ' || *s == '\t')
135			s++;
136		*pend = s;
137	}
138	if (neg)
139		return (-n);
140	return (n);
141}
142
143
144#if !HAVE_STRCHR
145	char *
146strchr(s, c)
147	char *s;
148	int c;
149{
150	for ( ;  *s != '\0';  s++)
151		if (*s == c)
152			return (s);
153	if (c == '\0')
154		return (s);
155	return (NULL);
156}
157#endif
158
159	int
160main(argc, argv)
161	int argc;
162	char *argv[];
163{
164	char *arg;
165	char *s;
166	int no_more_options;
167
168	no_more_options = 0;
169	while (--argc > 0)
170	{
171		arg = *++argv;
172		if (*arg != '-' || no_more_options)
173			break;
174		switch (*++arg)
175		{
176		case 'a':
177			quote_all = 1;
178			break;
179		case 'c':
180			closequote = *++arg;
181			break;
182		case 'd':
183			closequote = lstrtol(++arg, 0, &s);
184			if (s == arg)
185				pr_error("Missing number after -d");
186			break;
187		case 'e':
188			if (strcmp(++arg, "-") == 0)
189				meta_escape = "";
190			else
191				meta_escape = arg;
192			break;
193		case 'f':
194			meta_escape_buf[0] = lstrtol(++arg, 0, &s);
195			meta_escape = meta_escape_buf;
196			if (s == arg)
197				pr_error("Missing number after -f");
198			break;
199		case 'o':
200			openquote = *++arg;
201			break;
202		case 'p':
203			openquote = lstrtol(++arg, 0, &s);
204			if (s == arg)
205				pr_error("Missing number after -p");
206			break;
207		case 'm':
208			metachars[num_metachars++] = *++arg;
209			metachars[num_metachars] = '\0';
210			break;
211		case 'n':
212			metachars[num_metachars++] = lstrtol(++arg, 0, &s);
213			if (s == arg)
214				pr_error("Missing number after -n");
215			metachars[num_metachars] = '\0';
216			break;
217		case '?':
218			pr_usage();
219			return (0);
220		case '-':
221			if (*++arg == '\0')
222			{
223				no_more_options = 1;
224				break;
225			}
226			if (strcmp(arg, "version") == 0)
227			{
228				pr_version();
229				return (0);
230			}
231			if (strcmp(arg, "help") == 0)
232			{
233				pr_usage();
234				return (0);
235			}
236			pr_error("Invalid option after --");
237		default:
238			pr_error("Invalid option letter");
239		}
240	}
241
242	while (argc-- > 0)
243	{
244		int has_meta = 0;
245		arg = *argv++;
246		for (s = arg;  *s != '\0';  s++)
247		{
248			if (strchr(metachars, *s) != NULL)
249			{
250				has_meta = 1;
251				break;
252			}
253		}
254		if (quote_all || (has_meta && strlen(meta_escape) == 0))
255			printf("%c%s%c", openquote, arg, closequote);
256		else
257		{
258			for (s = arg;  *s != '\0';  s++)
259			{
260				if (strchr(metachars, *s) != NULL)
261					printf("%s", meta_escape);
262				printf("%c", *s);
263			}
264		}
265		if (argc > 0)
266			printf(" ");
267		else
268			printf("\n");
269	}
270	return (0);
271}
272