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.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 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