xref: /freebsd/contrib/less/lessecho.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
1 /*
2  * Copyright (C) 1984-2011  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 about less, or for information on how to
8  * contact the author, see the README file.
9  */
10 
11 
12 /*
13  * lessecho [-ox] [-cx] [-pn] [-dn] [-a] file ...
14  * Simply echos its filename arguments on standard output.
15  * But any argument containing spaces is enclosed in quotes.
16  *
17  * -ox	Specifies "x" to be the open quote character.
18  * -cx	Specifies "x" to be the close quote character.
19  * -pn	Specifies "n" to be the open quote character, as an integer.
20  * -dn	Specifies "n" to be the close quote character, as an integer.
21  * -mx  Specifies "x" to be a metachar.
22  * -nn  Specifies "n" to be a metachar, as an integer.
23  * -ex  Specifies "x" to be the escape char for metachars.
24  * -fn  Specifies "x" to be the escape char for metachars, as an integer.
25  * -a	Specifies that all arguments are to be quoted.
26  *	The default is that only arguments containing spaces are quoted.
27  */
28 
29 #include "less.h"
30 
31 static char *version = "$Revision: 1.14 $";
32 
33 static int quote_all = 0;
34 static char openquote = '"';
35 static char closequote = '"';
36 static char *meta_escape = "\\";
37 static char meta_escape_buf[2];
38 static char metachars[64] = "";
39 static int num_metachars = 0;
40 
41 	static void
42 pr_usage()
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()
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 
145 #if !HAVE_STRCHR
146 	char *
147 strchr(s, c)
148 	char *s;
149 	int c;
150 {
151 	for ( ;  *s != '\0';  s++)
152 		if (*s == c)
153 			return (s);
154 	if (c == '\0')
155 		return (s);
156 	return (NULL);
157 }
158 #endif
159 
160 	int
161 main(argc, argv)
162 	int argc;
163 	char *argv[];
164 {
165 	char *arg;
166 	char *s;
167 	int no_more_options;
168 
169 	no_more_options = 0;
170 	while (--argc > 0)
171 	{
172 		arg = *++argv;
173 		if (*arg != '-' || no_more_options)
174 			break;
175 		switch (*++arg)
176 		{
177 		case 'a':
178 			quote_all = 1;
179 			break;
180 		case 'c':
181 			closequote = *++arg;
182 			break;
183 		case 'd':
184 			closequote = lstrtol(++arg, 0, &s);
185 			if (s == arg)
186 				pr_error("Missing number after -d");
187 			break;
188 		case 'e':
189 			if (strcmp(++arg, "-") == 0)
190 				meta_escape = "";
191 			else
192 				meta_escape = arg;
193 			break;
194 		case 'f':
195 			meta_escape_buf[0] = lstrtol(++arg, 0, &s);
196 			meta_escape = meta_escape_buf;
197 			if (s == arg)
198 				pr_error("Missing number after -f");
199 			break;
200 		case 'o':
201 			openquote = *++arg;
202 			break;
203 		case 'p':
204 			openquote = lstrtol(++arg, 0, &s);
205 			if (s == arg)
206 				pr_error("Missing number after -p");
207 			break;
208 		case 'm':
209 			metachars[num_metachars++] = *++arg;
210 			metachars[num_metachars] = '\0';
211 			break;
212 		case 'n':
213 			metachars[num_metachars++] = lstrtol(++arg, 0, &s);
214 			if (s == arg)
215 				pr_error("Missing number after -n");
216 			metachars[num_metachars] = '\0';
217 			break;
218 		case '?':
219 			pr_usage();
220 			return (0);
221 		case '-':
222 			if (*++arg == '\0')
223 			{
224 				no_more_options = 1;
225 				break;
226 			}
227 			if (strcmp(arg, "version") == 0)
228 			{
229 				pr_version();
230 				return (0);
231 			}
232 			if (strcmp(arg, "help") == 0)
233 			{
234 				pr_usage();
235 				return (0);
236 			}
237 			pr_error("Invalid option after --");
238 		default:
239 			pr_error("Invalid option letter");
240 		}
241 	}
242 
243 	while (argc-- > 0)
244 	{
245 		int has_meta = 0;
246 		arg = *argv++;
247 		for (s = arg;  *s != '\0';  s++)
248 		{
249 			if (strchr(metachars, *s) != NULL)
250 			{
251 				has_meta = 1;
252 				break;
253 			}
254 		}
255 		if (quote_all || (has_meta && strlen(meta_escape) == 0))
256 			printf("%c%s%c", openquote, arg, closequote);
257 		else
258 		{
259 			for (s = arg;  *s != '\0';  s++)
260 			{
261 				if (strchr(metachars, *s) != NULL)
262 					printf("%s", meta_escape);
263 				printf("%c", *s);
264 			}
265 		}
266 		if (argc > 0)
267 			printf(" ");
268 		else
269 			printf("\n");
270 	}
271 	return (0);
272 }
273