xref: /dragonfly/contrib/less/lessecho.c (revision e0f238eda64c20d98364903e0c003825fd0b66dd)
1 /*
2  * Copyright (C) 1984-2024  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(char ch)136 static void add_metachar(char 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_t) 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 = (char) 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] = (char) 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 = (char) 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((char) 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                               return (0);
249                     default:
250                               pr_error("Invalid option letter");
251                     }
252           }
253 
254           while (argc-- > 0)
255           {
256                     int has_meta = 0;
257                     arg = *argv++;
258                     for (s = arg;  *s != '\0';  s++)
259                     {
260                               if (is_metachar(*s))
261                               {
262                                         has_meta = 1;
263                                         break;
264                               }
265                     }
266                     if (quote_all || (has_meta && strlen(meta_escape) == 0))
267                               printf("%c%s%c", openquote, arg, closequote);
268                     else
269                     {
270                               for (s = arg;  *s != '\0';  s++)
271                               {
272                                         if (is_metachar(*s))
273                                                   printf("%s", meta_escape);
274                                         printf("%c", *s);
275                               }
276                     }
277                     if (argc > 0)
278                               printf(" ");
279                     else
280                               printf("\n");
281           }
282           return (0);
283 }
284