1 /* 2 * Copyright (C) 1984-2022 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 42 pr_usage(VOID_PARAM) 43 { 44 fprintf(stderr, 45 "usage: lessecho [-ox] [-cx] [-pn] [-dn] [-mx] [-nn] [-ex] [-fn] [-a] file ...\n"); 46 } 47 48 static void 49 pr_version(VOID_PARAM) 50 { 51 char *p; 52 char buf[10]; 53 char *pbuf = buf; 54 55 for (p = version; *p != ' '; p++) 56 if (*p == '\0') 57 return; 58 for (p++; *p != '$' && *p != ' ' && *p != '\0'; p++) 59 *pbuf++ = *p; 60 *pbuf = '\0'; 61 printf("%s\n", buf); 62 } 63 64 static void 65 pr_error(s) 66 char *s; 67 { 68 fprintf(stderr, "%s\n", s); 69 exit(1); 70 } 71 72 static long 73 lstrtol(s, radix, pend) 74 char *s; 75 int radix; 76 char **pend; 77 { 78 int v; 79 int neg = 0; 80 long n = 0; 81 82 /* Skip leading white space. */ 83 while (*s == ' ' || *s == '\t') 84 s++; 85 86 /* Check for a leading + or -. */ 87 if (*s == '-') 88 { 89 neg = 1; 90 s++; 91 } else if (*s == '+') 92 { 93 s++; 94 } 95 96 /* Determine radix if caller does not specify. */ 97 if (radix == 0) 98 { 99 radix = 10; 100 if (*s == '0') 101 { 102 switch (*++s) 103 { 104 case 'x': 105 radix = 16; 106 s++; 107 break; 108 default: 109 radix = 8; 110 break; 111 } 112 } 113 } 114 115 /* Parse the digits of the number. */ 116 for (;;) 117 { 118 if (*s >= '0' && *s <= '9') 119 v = *s - '0'; 120 else if (*s >= 'a' && *s <= 'f') 121 v = *s - 'a' + 10; 122 else if (*s >= 'A' && *s <= 'F') 123 v = *s - 'A' + 10; 124 else 125 break; 126 if (v >= radix) 127 break; 128 n = n * radix + v; 129 s++; 130 } 131 132 if (pend != NULL) 133 { 134 /* Skip trailing white space. */ 135 while (*s == ' ' || *s == '\t') 136 s++; 137 *pend = s; 138 } 139 if (neg) 140 return (-n); 141 return (n); 142 } 143 144 static void 145 add_metachar(ch) 146 int ch; 147 { 148 if (num_metachars+1 >= size_metachars) 149 { 150 char *p; 151 size_metachars = (size_metachars > 0) ? size_metachars*2 : 16; 152 p = (char *) malloc(size_metachars); 153 if (p == NULL) 154 pr_error("Cannot allocate memory"); 155 156 if (metachars != NULL) 157 { 158 strcpy(p, metachars); 159 free(metachars); 160 } 161 metachars = p; 162 } 163 metachars[num_metachars++] = ch; 164 metachars[num_metachars] = '\0'; 165 } 166 167 static int 168 is_metachar(ch) 169 int ch; 170 { 171 return (metachars != NULL && strchr(metachars, ch) != NULL); 172 } 173 174 #if !HAVE_STRCHR 175 char * 176 strchr(s, c) 177 char *s; 178 int c; 179 { 180 for ( ; *s != '\0'; s++) 181 if (*s == c) 182 return (s); 183 if (c == '\0') 184 return (s); 185 return (NULL); 186 } 187 #endif 188 189 int 190 main(argc, argv) 191 int argc; 192 char *argv[]; 193 { 194 char *arg; 195 char *s; 196 int no_more_options; 197 198 no_more_options = 0; 199 while (--argc > 0) 200 { 201 arg = *++argv; 202 if (*arg != '-' || no_more_options) 203 break; 204 switch (*++arg) 205 { 206 case 'a': 207 quote_all = 1; 208 break; 209 case 'c': 210 closequote = *++arg; 211 break; 212 case 'd': 213 closequote = lstrtol(++arg, 0, &s); 214 if (s == arg) 215 pr_error("Missing number after -d"); 216 break; 217 case 'e': 218 if (strcmp(++arg, "-") == 0) 219 meta_escape = ""; 220 else 221 meta_escape = arg; 222 break; 223 case 'f': 224 meta_escape_buf[0] = lstrtol(++arg, 0, &s); 225 meta_escape_buf[1] = '\0'; 226 meta_escape = meta_escape_buf; 227 if (s == arg) 228 pr_error("Missing number after -f"); 229 break; 230 case 'o': 231 openquote = *++arg; 232 break; 233 case 'p': 234 openquote = lstrtol(++arg, 0, &s); 235 if (s == arg) 236 pr_error("Missing number after -p"); 237 break; 238 case 'm': 239 add_metachar(*++arg); 240 break; 241 case 'n': 242 add_metachar(lstrtol(++arg, 0, &s)); 243 if (s == arg) 244 pr_error("Missing number after -n"); 245 break; 246 case '?': 247 pr_usage(); 248 return (0); 249 case '-': 250 if (*++arg == '\0') 251 { 252 no_more_options = 1; 253 break; 254 } 255 if (strcmp(arg, "version") == 0) 256 { 257 pr_version(); 258 return (0); 259 } 260 if (strcmp(arg, "help") == 0) 261 { 262 pr_usage(); 263 return (0); 264 } 265 pr_error("Invalid option after --"); 266 default: 267 pr_error("Invalid option letter"); 268 } 269 } 270 271 while (argc-- > 0) 272 { 273 int has_meta = 0; 274 arg = *argv++; 275 for (s = arg; *s != '\0'; s++) 276 { 277 if (is_metachar(*s)) 278 { 279 has_meta = 1; 280 break; 281 } 282 } 283 if (quote_all || (has_meta && strlen(meta_escape) == 0)) 284 printf("%c%s%c", openquote, arg, closequote); 285 else 286 { 287 for (s = arg; *s != '\0'; s++) 288 { 289 if (is_metachar(*s)) 290 printf("%s", meta_escape); 291 printf("%c", *s); 292 } 293 } 294 if (argc > 0) 295 printf(" "); 296 else 297 printf("\n"); 298 } 299 return (0); 300 } 301