xref: /freebsd/contrib/less/lessecho.c (revision 9768746ba83efa02837c5b9c66348db6e900208f)
1 /*
2  * Copyright (C) 1984-2022  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 
30 static char *version = "$Revision: 1.15 $";
31 
32 static int quote_all = 0;
33 static char openquote = '"';
34 static char closequote = '"';
35 static char *meta_escape = "\\";
36 static char meta_escape_buf[2];
37 static char* metachars = NULL;
38 static int num_metachars = 0;
39 static int size_metachars = 0;
40 
41 	static void
42 pr_usage(VOID_PARAM)
43 {
44 	fprintf(stderr,
45 		"usage: lessecho [-ox] [-cx] [-pn] [-dn] [-mx] [-nn] [-ex] [-fn] [-a] file ...\n");
46 }
47 
48 	static void
49 pr_version(VOID_PARAM)
50 {
51 	char *p;
52 	char buf[10];
53 	char *pbuf = buf;
54 
55 	for (p = version;  *p != ' ';  p++)
56 		if (*p == '\0')
57 			return;
58 	for (p++;  *p != '$' && *p != ' ' && *p != '\0';  p++)
59 		*pbuf++ = *p;
60 	*pbuf = '\0';
61 	printf("%s\n", buf);
62 }
63 
64 	static void
65 pr_error(s)
66 	char *s;
67 {
68 	fprintf(stderr, "%s\n", s);
69 	exit(1);
70 }
71 
72 	static long
73 lstrtol(s, radix, pend)
74 	char *s;
75 	int radix;
76 	char **pend;
77 {
78 	int v;
79 	int neg = 0;
80 	long n = 0;
81 
82 	/* Skip leading white space. */
83 	while (*s == ' ' || *s == '\t')
84 		s++;
85 
86 	/* Check for a leading + or -. */
87 	if (*s == '-')
88 	{
89 		neg = 1;
90 		s++;
91 	} else if (*s == '+')
92 	{
93 		s++;
94 	}
95 
96 	/* Determine radix if caller does not specify. */
97 	if (radix == 0)
98 	{
99 		radix = 10;
100 		if (*s == '0')
101 		{
102 			switch (*++s)
103 			{
104 			case 'x':
105 				radix = 16;
106 				s++;
107 				break;
108 			default:
109 				radix = 8;
110 				break;
111 			}
112 		}
113 	}
114 
115 	/* Parse the digits of the number. */
116 	for (;;)
117 	{
118 		if (*s >= '0' && *s <= '9')
119 			v = *s - '0';
120 		else if (*s >= 'a' && *s <= 'f')
121 			v = *s - 'a' + 10;
122 		else if (*s >= 'A' && *s <= 'F')
123 			v = *s - 'A' + 10;
124 		else
125 			break;
126 		if (v >= radix)
127 			break;
128 		n = n * radix + v;
129 		s++;
130 	}
131 
132 	if (pend != NULL)
133 	{
134 		/* Skip trailing white space. */
135 		while (*s == ' ' || *s == '\t')
136 			s++;
137 		*pend = s;
138 	}
139 	if (neg)
140 		return (-n);
141 	return (n);
142 }
143 
144 	static void
145 add_metachar(ch)
146 	int ch;
147 {
148 	if (num_metachars+1 >= size_metachars)
149 	{
150 		char *p;
151 		size_metachars = (size_metachars > 0) ? size_metachars*2 : 16;
152 		p = (char *) malloc(size_metachars);
153 		if (p == NULL)
154 			pr_error("Cannot allocate memory");
155 
156 		if (metachars != NULL)
157 		{
158 			strcpy(p, metachars);
159 			free(metachars);
160 		}
161 		metachars = p;
162 	}
163 	metachars[num_metachars++] = ch;
164 	metachars[num_metachars] = '\0';
165 }
166 
167 	static int
168 is_metachar(ch)
169 	int ch;
170 {
171 	return (metachars != NULL && strchr(metachars, ch) != NULL);
172 }
173 
174 #if !HAVE_STRCHR
175 	char *
176 strchr(s, c)
177 	char *s;
178 	int c;
179 {
180 	for ( ;  *s != '\0';  s++)
181 		if (*s == c)
182 			return (s);
183 	if (c == '\0')
184 		return (s);
185 	return (NULL);
186 }
187 #endif
188 
189 	int
190 main(argc, argv)
191 	int argc;
192 	char *argv[];
193 {
194 	char *arg;
195 	char *s;
196 	int no_more_options;
197 
198 	no_more_options = 0;
199 	while (--argc > 0)
200 	{
201 		arg = *++argv;
202 		if (*arg != '-' || no_more_options)
203 			break;
204 		switch (*++arg)
205 		{
206 		case 'a':
207 			quote_all = 1;
208 			break;
209 		case 'c':
210 			closequote = *++arg;
211 			break;
212 		case 'd':
213 			closequote = lstrtol(++arg, 0, &s);
214 			if (s == arg)
215 				pr_error("Missing number after -d");
216 			break;
217 		case 'e':
218 			if (strcmp(++arg, "-") == 0)
219 				meta_escape = "";
220 			else
221 				meta_escape = arg;
222 			break;
223 		case 'f':
224 			meta_escape_buf[0] = lstrtol(++arg, 0, &s);
225 			meta_escape_buf[1] = '\0';
226 			meta_escape = meta_escape_buf;
227 			if (s == arg)
228 				pr_error("Missing number after -f");
229 			break;
230 		case 'o':
231 			openquote = *++arg;
232 			break;
233 		case 'p':
234 			openquote = lstrtol(++arg, 0, &s);
235 			if (s == arg)
236 				pr_error("Missing number after -p");
237 			break;
238 		case 'm':
239 			add_metachar(*++arg);
240 			break;
241 		case 'n':
242 			add_metachar(lstrtol(++arg, 0, &s));
243 			if (s == arg)
244 				pr_error("Missing number after -n");
245 			break;
246 		case '?':
247 			pr_usage();
248 			return (0);
249 		case '-':
250 			if (*++arg == '\0')
251 			{
252 				no_more_options = 1;
253 				break;
254 			}
255 			if (strcmp(arg, "version") == 0)
256 			{
257 				pr_version();
258 				return (0);
259 			}
260 			if (strcmp(arg, "help") == 0)
261 			{
262 				pr_usage();
263 				return (0);
264 			}
265 			pr_error("Invalid option after --");
266 		default:
267 			pr_error("Invalid option letter");
268 		}
269 	}
270 
271 	while (argc-- > 0)
272 	{
273 		int has_meta = 0;
274 		arg = *argv++;
275 		for (s = arg;  *s != '\0';  s++)
276 		{
277 			if (is_metachar(*s))
278 			{
279 				has_meta = 1;
280 				break;
281 			}
282 		}
283 		if (quote_all || (has_meta && strlen(meta_escape) == 0))
284 			printf("%c%s%c", openquote, arg, closequote);
285 		else
286 		{
287 			for (s = arg;  *s != '\0';  s++)
288 			{
289 				if (is_metachar(*s))
290 					printf("%s", meta_escape);
291 				printf("%c", *s);
292 			}
293 		}
294 		if (argc > 0)
295 			printf(" ");
296 		else
297 			printf("\n");
298 	}
299 	return (0);
300 }
301