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