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