xref: /netbsd-src/external/bsd/less/dist/lessecho.c (revision 838f5788460f0f133b15d706e644d692a9d4d6ec)
1*838f5788Ssimonb /*	$NetBSD: lessecho.c,v 1.5 2023/10/06 05:49:49 simonb Exp $	*/
220006a0bStron 
320006a0bStron /*
4*838f5788Ssimonb  * Copyright (C) 1984-2023  Mark Nudelman
520006a0bStron  *
620006a0bStron  * You may distribute under the terms of either the GNU General Public
720006a0bStron  * License or the Less License, as specified in the README file.
820006a0bStron  *
9ec18bca0Stron  * For more information, see the README file.
1020006a0bStron  */
1120006a0bStron 
1220006a0bStron 
1320006a0bStron /*
1420006a0bStron  * lessecho [-ox] [-cx] [-pn] [-dn] [-a] file ...
1520006a0bStron  * Simply echos its filename arguments on standard output.
1620006a0bStron  * But any argument containing spaces is enclosed in quotes.
1720006a0bStron  *
1820006a0bStron  * -ox  Specifies "x" to be the open quote character.
1920006a0bStron  * -cx  Specifies "x" to be the close quote character.
2020006a0bStron  * -pn  Specifies "n" to be the open quote character, as an integer.
2120006a0bStron  * -dn  Specifies "n" to be the close quote character, as an integer.
2220006a0bStron  * -mx  Specifies "x" to be a metachar.
2320006a0bStron  * -nn  Specifies "n" to be a metachar, as an integer.
2420006a0bStron  * -ex  Specifies "x" to be the escape char for metachars.
2520006a0bStron  * -fn  Specifies "x" to be the escape char for metachars, as an integer.
2620006a0bStron  * -a   Specifies that all arguments are to be quoted.
2720006a0bStron  *      The default is that only arguments containing spaces are quoted.
2820006a0bStron  */
2920006a0bStron 
3020006a0bStron #include "less.h"
3120006a0bStron 
32*838f5788Ssimonb static char *version = "$Revision: 1.5 $";
3320006a0bStron 
3420006a0bStron static int quote_all = 0;
3520006a0bStron static char openquote = '"';
3620006a0bStron static char closequote = '"';
3720006a0bStron static char *meta_escape = "\\";
3820006a0bStron static char meta_escape_buf[2];
39*838f5788Ssimonb static char* metachars = NULL;
4020006a0bStron static int num_metachars = 0;
41*838f5788Ssimonb static int size_metachars = 0;
4220006a0bStron 
pr_usage(void)43*838f5788Ssimonb static void pr_usage(void)
4420006a0bStron {
4520006a0bStron 	fprintf(stderr,
4620006a0bStron 		"usage: lessecho [-ox] [-cx] [-pn] [-dn] [-mx] [-nn] [-ex] [-fn] [-a] file ...\n");
4720006a0bStron }
4820006a0bStron 
pr_version(void)49*838f5788Ssimonb static void pr_version(void)
5020006a0bStron {
5120006a0bStron 	char *p;
5220006a0bStron 	char buf[10];
5320006a0bStron 	char *pbuf = buf;
5420006a0bStron 
5520006a0bStron 	for (p = version;  *p != ' ';  p++)
5620006a0bStron 		if (*p == '\0')
5720006a0bStron 			return;
5820006a0bStron 	for (p++;  *p != '$' && *p != ' ' && *p != '\0';  p++)
5920006a0bStron 		*pbuf++ = *p;
6020006a0bStron 	*pbuf = '\0';
6120006a0bStron 	printf("%s\n", buf);
6220006a0bStron }
6320006a0bStron 
pr_error(char * s)64*838f5788Ssimonb static void pr_error(char *s)
6520006a0bStron {
6620006a0bStron 	fprintf(stderr, "%s\n", s);
6720006a0bStron 	exit(1);
6820006a0bStron }
6920006a0bStron 
lstrtol(char * s,char ** pend,int radix)70*838f5788Ssimonb static long lstrtol(char *s, char **pend, int radix)
7120006a0bStron {
7220006a0bStron 	int v;
7320006a0bStron 	int neg = 0;
7420006a0bStron 	long n = 0;
7520006a0bStron 
7620006a0bStron 	/* Skip leading white space. */
7720006a0bStron 	while (*s == ' ' || *s == '\t')
7820006a0bStron 		s++;
7920006a0bStron 
8020006a0bStron 	/* Check for a leading + or -. */
8120006a0bStron 	if (*s == '-')
8220006a0bStron 	{
8320006a0bStron 		neg = 1;
8420006a0bStron 		s++;
8520006a0bStron 	} else if (*s == '+')
8620006a0bStron 	{
8720006a0bStron 		s++;
8820006a0bStron 	}
8920006a0bStron 
9020006a0bStron 	/* Determine radix if caller does not specify. */
9120006a0bStron 	if (radix == 0)
9220006a0bStron 	{
9320006a0bStron 		radix = 10;
9420006a0bStron 		if (*s == '0')
9520006a0bStron 		{
9620006a0bStron 			switch (*++s)
9720006a0bStron 			{
9820006a0bStron 			case 'x':
9920006a0bStron 				radix = 16;
10020006a0bStron 				s++;
10120006a0bStron 				break;
10220006a0bStron 			default:
10320006a0bStron 				radix = 8;
10420006a0bStron 				break;
10520006a0bStron 			}
10620006a0bStron 		}
10720006a0bStron 	}
10820006a0bStron 
10920006a0bStron 	/* Parse the digits of the number. */
11020006a0bStron 	for (;;)
11120006a0bStron 	{
11220006a0bStron 		if (*s >= '0' && *s <= '9')
11320006a0bStron 			v = *s - '0';
11420006a0bStron 		else if (*s >= 'a' && *s <= 'f')
11520006a0bStron 			v = *s - 'a' + 10;
11620006a0bStron 		else if (*s >= 'A' && *s <= 'F')
11720006a0bStron 			v = *s - 'A' + 10;
11820006a0bStron 		else
11920006a0bStron 			break;
12020006a0bStron 		if (v >= radix)
12120006a0bStron 			break;
12220006a0bStron 		n = n * radix + v;
12320006a0bStron 		s++;
12420006a0bStron 	}
12520006a0bStron 
12620006a0bStron 	if (pend != NULL)
12720006a0bStron 	{
12820006a0bStron 		/* Skip trailing white space. */
12920006a0bStron 		while (*s == ' ' || *s == '\t')
13020006a0bStron 			s++;
13120006a0bStron 		*pend = s;
13220006a0bStron 	}
13320006a0bStron 	if (neg)
13420006a0bStron 		return (-n);
13520006a0bStron 	return (n);
13620006a0bStron }
13720006a0bStron 
add_metachar(int ch)138*838f5788Ssimonb static void add_metachar(int ch)
139*838f5788Ssimonb {
140*838f5788Ssimonb 	if (num_metachars+1 >= size_metachars)
141*838f5788Ssimonb 	{
142*838f5788Ssimonb 		char *p;
143*838f5788Ssimonb 		size_metachars = (size_metachars > 0) ? size_metachars*2 : 16;
144*838f5788Ssimonb 		p = (char *) malloc(size_metachars);
145*838f5788Ssimonb 		if (p == NULL)
146*838f5788Ssimonb 			pr_error("Cannot allocate memory");
147*838f5788Ssimonb 
148*838f5788Ssimonb 		if (metachars != NULL)
149*838f5788Ssimonb 		{
150*838f5788Ssimonb 			strcpy(p, metachars);
151*838f5788Ssimonb 			free(metachars);
152*838f5788Ssimonb 		}
153*838f5788Ssimonb 		metachars = p;
154*838f5788Ssimonb 	}
155*838f5788Ssimonb 	metachars[num_metachars++] = ch;
156*838f5788Ssimonb 	metachars[num_metachars] = '\0';
157*838f5788Ssimonb }
158*838f5788Ssimonb 
is_metachar(int ch)159*838f5788Ssimonb static int is_metachar(int ch)
160*838f5788Ssimonb {
161*838f5788Ssimonb 	return (metachars != NULL && strchr(metachars, ch) != NULL);
162*838f5788Ssimonb }
16320006a0bStron 
16420006a0bStron #if !HAVE_STRCHR
strchr(char * s,char c)165*838f5788Ssimonb char * strchr(char *s, char c)
16620006a0bStron {
16720006a0bStron 	for ( ;  *s != '\0';  s++)
16820006a0bStron 		if (*s == c)
16920006a0bStron 			return (s);
17020006a0bStron 	if (c == '\0')
17120006a0bStron 		return (s);
17220006a0bStron 	return (NULL);
17320006a0bStron }
17420006a0bStron #endif
17520006a0bStron 
main(int argc,char * argv[])176*838f5788Ssimonb int main(int argc, char *argv[])
17720006a0bStron {
17820006a0bStron 	char *arg;
17920006a0bStron 	char *s;
18020006a0bStron 	int no_more_options;
18120006a0bStron 
18220006a0bStron 	no_more_options = 0;
18320006a0bStron 	while (--argc > 0)
18420006a0bStron 	{
18520006a0bStron 		arg = *++argv;
18620006a0bStron 		if (*arg != '-' || no_more_options)
18720006a0bStron 			break;
18820006a0bStron 		switch (*++arg)
18920006a0bStron 		{
19020006a0bStron 		case 'a':
19120006a0bStron 			quote_all = 1;
19220006a0bStron 			break;
19320006a0bStron 		case 'c':
19420006a0bStron 			closequote = *++arg;
19520006a0bStron 			break;
19620006a0bStron 		case 'd':
197*838f5788Ssimonb 			closequote = lstrtol(++arg, &s, 0);
19820006a0bStron 			if (s == arg)
19920006a0bStron 				pr_error("Missing number after -d");
20020006a0bStron 			break;
20120006a0bStron 		case 'e':
20220006a0bStron 			if (strcmp(++arg, "-") == 0)
20320006a0bStron 				meta_escape = "";
20420006a0bStron 			else
20520006a0bStron 				meta_escape = arg;
20620006a0bStron 			break;
20720006a0bStron 		case 'f':
208*838f5788Ssimonb 			meta_escape_buf[0] = lstrtol(++arg, &s, 0);
209*838f5788Ssimonb 			meta_escape_buf[1] = '\0';
21020006a0bStron 			meta_escape = meta_escape_buf;
21120006a0bStron 			if (s == arg)
21220006a0bStron 				pr_error("Missing number after -f");
21320006a0bStron 			break;
21420006a0bStron 		case 'o':
21520006a0bStron 			openquote = *++arg;
21620006a0bStron 			break;
21720006a0bStron 		case 'p':
218*838f5788Ssimonb 			openquote = lstrtol(++arg, &s, 0);
21920006a0bStron 			if (s == arg)
22020006a0bStron 				pr_error("Missing number after -p");
22120006a0bStron 			break;
22220006a0bStron 		case 'm':
223*838f5788Ssimonb 			add_metachar(*++arg);
22420006a0bStron 			break;
22520006a0bStron 		case 'n':
226*838f5788Ssimonb 			add_metachar(lstrtol(++arg, &s, 0));
22720006a0bStron 			if (s == arg)
22820006a0bStron 				pr_error("Missing number after -n");
22920006a0bStron 			break;
23020006a0bStron 		case '?':
23120006a0bStron 			pr_usage();
23220006a0bStron 			return (0);
23320006a0bStron 		case '-':
23420006a0bStron 			if (*++arg == '\0')
23520006a0bStron 			{
23620006a0bStron 				no_more_options = 1;
23720006a0bStron 				break;
23820006a0bStron 			}
23920006a0bStron 			if (strcmp(arg, "version") == 0)
24020006a0bStron 			{
24120006a0bStron 				pr_version();
24220006a0bStron 				return (0);
24320006a0bStron 			}
24420006a0bStron 			if (strcmp(arg, "help") == 0)
24520006a0bStron 			{
24620006a0bStron 				pr_usage();
24720006a0bStron 				return (0);
24820006a0bStron 			}
24920006a0bStron 			pr_error("Invalid option after --");
25020006a0bStron 		default:
25120006a0bStron 			pr_error("Invalid option letter");
25220006a0bStron 		}
25320006a0bStron 	}
25420006a0bStron 
25520006a0bStron 	while (argc-- > 0)
25620006a0bStron 	{
25720006a0bStron 		int has_meta = 0;
25820006a0bStron 		arg = *argv++;
25920006a0bStron 		for (s = arg;  *s != '\0';  s++)
26020006a0bStron 		{
261*838f5788Ssimonb 			if (is_metachar(*s))
26220006a0bStron 			{
26320006a0bStron 				has_meta = 1;
26420006a0bStron 				break;
26520006a0bStron 			}
26620006a0bStron 		}
26720006a0bStron 		if (quote_all || (has_meta && strlen(meta_escape) == 0))
26820006a0bStron 			printf("%c%s%c", openquote, arg, closequote);
26920006a0bStron 		else
27020006a0bStron 		{
27120006a0bStron 			for (s = arg;  *s != '\0';  s++)
27220006a0bStron 			{
273*838f5788Ssimonb 				if (is_metachar(*s))
27420006a0bStron 					printf("%s", meta_escape);
27520006a0bStron 				printf("%c", *s);
27620006a0bStron 			}
27720006a0bStron 		}
27820006a0bStron 		if (argc > 0)
27920006a0bStron 			printf(" ");
28020006a0bStron 		else
28120006a0bStron 			printf("\n");
28220006a0bStron 	}
28320006a0bStron 	return (0);
28420006a0bStron }
285