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