xref: /freebsd/contrib/less/lessecho.c (revision fe6060f10f634930ff71b7c50291ddc610da2475)
1 /*
2  * Copyright (C) 1984-2021  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[64] = "";
38 static int num_metachars = 0;
39 
40 	static void
41 pr_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
48 pr_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
64 pr_error(s)
65 	char *s;
66 {
67 	fprintf(stderr, "%s\n", s);
68 	exit(1);
69 }
70 
71 	static long
72 lstrtol(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 *
146 strchr(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
160 main(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