Home | History | Annotate | Line # | Download | only in dist
      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