Home | History | Annotate | Line # | Download | only in dist
lessecho.c revision 1.1.1.3
      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.1.1.3 $";
     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 
     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 
     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 
     62 static void pr_error(char *s)
     63 {
     64 	fprintf(stderr, "%s\n", s);
     65 	exit(1);
     66 }
     67 
     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 
    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 
    157 static int is_metachar(int ch)
    158 {
    159 	return (metachars != NULL && strchr(metachars, ch) != NULL);
    160 }
    161 
    162 #if !HAVE_STRCHR
    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 
    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