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