xref: /freebsd/contrib/less/lessecho.c (revision e3514747256465c52c3b2aedc9795f52c0d3efe9)
1 /*
2  * Copyright (C) 1984-2015  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)
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)
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(char *s)
65 {
66 	fprintf(stderr, "%s\n", s);
67 	exit(1);
68 }
69 
70 	static long
71 lstrtol(char *s, int radix, char **pend)
72 {
73 	int v;
74 	int neg = 0;
75 	long n = 0;
76 
77 	/* Skip leading white space. */
78 	while (*s == ' ' || *s == '\t')
79 		s++;
80 
81 	/* Check for a leading + or -. */
82 	if (*s == '-')
83 	{
84 		neg = 1;
85 		s++;
86 	} else if (*s == '+')
87 	{
88 		s++;
89 	}
90 
91 	/* Determine radix if caller does not specify. */
92 	if (radix == 0)
93 	{
94 		radix = 10;
95 		if (*s == '0')
96 		{
97 			switch (*++s)
98 			{
99 			case 'x':
100 				radix = 16;
101 				s++;
102 				break;
103 			default:
104 				radix = 8;
105 				break;
106 			}
107 		}
108 	}
109 
110 	/* Parse the digits of the number. */
111 	for (;;)
112 	{
113 		if (*s >= '0' && *s <= '9')
114 			v = *s - '0';
115 		else if (*s >= 'a' && *s <= 'f')
116 			v = *s - 'a' + 10;
117 		else if (*s >= 'A' && *s <= 'F')
118 			v = *s - 'A' + 10;
119 		else
120 			break;
121 		if (v >= radix)
122 			break;
123 		n = n * radix + v;
124 		s++;
125 	}
126 
127 	if (pend != NULL)
128 	{
129 		/* Skip trailing white space. */
130 		while (*s == ' ' || *s == '\t')
131 			s++;
132 		*pend = s;
133 	}
134 	if (neg)
135 		return (-n);
136 	return (n);
137 }
138 
139 
140 #if !HAVE_STRCHR
141 	char *
142 strchr(s, c)
143 	char *s;
144 	int c;
145 {
146 	for ( ;  *s != '\0';  s++)
147 		if (*s == c)
148 			return (s);
149 	if (c == '\0')
150 		return (s);
151 	return (NULL);
152 }
153 #endif
154 
155 	int
156 main(argc, argv)
157 	int argc;
158 	char *argv[];
159 {
160 	char *arg;
161 	char *s;
162 	int no_more_options;
163 
164 	no_more_options = 0;
165 	while (--argc > 0)
166 	{
167 		arg = *++argv;
168 		if (*arg != '-' || no_more_options)
169 			break;
170 		switch (*++arg)
171 		{
172 		case 'a':
173 			quote_all = 1;
174 			break;
175 		case 'c':
176 			closequote = *++arg;
177 			break;
178 		case 'd':
179 			closequote = lstrtol(++arg, 0, &s);
180 			if (s == arg)
181 				pr_error("Missing number after -d");
182 			break;
183 		case 'e':
184 			if (strcmp(++arg, "-") == 0)
185 				meta_escape = "";
186 			else
187 				meta_escape = arg;
188 			break;
189 		case 'f':
190 			meta_escape_buf[0] = lstrtol(++arg, 0, &s);
191 			meta_escape = meta_escape_buf;
192 			if (s == arg)
193 				pr_error("Missing number after -f");
194 			break;
195 		case 'o':
196 			openquote = *++arg;
197 			break;
198 		case 'p':
199 			openquote = lstrtol(++arg, 0, &s);
200 			if (s == arg)
201 				pr_error("Missing number after -p");
202 			break;
203 		case 'm':
204 			metachars[num_metachars++] = *++arg;
205 			metachars[num_metachars] = '\0';
206 			break;
207 		case 'n':
208 			metachars[num_metachars++] = lstrtol(++arg, 0, &s);
209 			if (s == arg)
210 				pr_error("Missing number after -n");
211 			metachars[num_metachars] = '\0';
212 			break;
213 		case '?':
214 			pr_usage();
215 			return (0);
216 		case '-':
217 			if (*++arg == '\0')
218 			{
219 				no_more_options = 1;
220 				break;
221 			}
222 			if (strcmp(arg, "version") == 0)
223 			{
224 				pr_version();
225 				return (0);
226 			}
227 			if (strcmp(arg, "help") == 0)
228 			{
229 				pr_usage();
230 				return (0);
231 			}
232 			pr_error("Invalid option after --");
233 		default:
234 			pr_error("Invalid option letter");
235 		}
236 	}
237 
238 	while (argc-- > 0)
239 	{
240 		int has_meta = 0;
241 		arg = *argv++;
242 		for (s = arg;  *s != '\0';  s++)
243 		{
244 			if (strchr(metachars, *s) != NULL)
245 			{
246 				has_meta = 1;
247 				break;
248 			}
249 		}
250 		if (quote_all || (has_meta && strlen(meta_escape) == 0))
251 			printf("%c%s%c", openquote, arg, closequote);
252 		else
253 		{
254 			for (s = arg;  *s != '\0';  s++)
255 			{
256 				if (strchr(metachars, *s) != NULL)
257 					printf("%s", meta_escape);
258 				printf("%c", *s);
259 			}
260 		}
261 		if (argc > 0)
262 			printf(" ");
263 		else
264 			printf("\n");
265 	}
266 	return (0);
267 }
268