1 /* 2 * Copyright (C) 1984-2012 Mark Nudelman 3 * Modified for use with illumos by Garrett D'Amore. 4 * Copyright 2014 Garrett D'Amore <garrett@damore.org> 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Less License, as specified in the README file. 8 * 9 * For more information, see the README file. 10 */ 11 12 /* 13 * Entry point, initialization, miscellaneous routines. 14 */ 15 16 #include <sys/types.h> 17 18 #include <libgen.h> 19 #include <stdarg.h> 20 21 #include "less.h" 22 23 char *every_first_cmd = NULL; 24 int new_file; 25 int is_tty; 26 IFILE curr_ifile = NULL; 27 IFILE old_ifile = NULL; 28 struct scrpos initial_scrpos; 29 int any_display = FALSE; 30 off_t start_attnpos = -1; 31 off_t end_attnpos = -1; 32 int wscroll; 33 34 static char *progname; 35 36 int quitting; 37 int secure; 38 int dohelp; 39 40 int logfile = -1; 41 int force_logfile = FALSE; 42 char *namelogfile = NULL; 43 char *editor; 44 char *editproto; 45 46 extern char *tags; 47 extern char *tagoption; 48 extern int jump_sline; 49 extern int less_is_more; 50 extern int missing_cap; 51 extern int know_dumb; 52 extern int quit_if_one_screen; 53 extern int quit_at_eof; 54 extern int pr_type; 55 extern int hilite_search; 56 extern int no_init; 57 extern int top_scroll; 58 extern int errmsgs; 59 60 61 /* 62 * Entry point. 63 */ 64 int 65 main(int argc, char *argv[]) 66 { 67 IFILE ifile; 68 char *s; 69 70 progname = basename(argv[0]); 71 argv++; 72 argc--; 73 74 /* 75 * If the name of the executable program is "more", 76 * act like LESS_IS_MORE is set. We have to set this as early 77 * as possible for POSIX. 78 */ 79 if (strcmp(progname, "more") == 0) 80 less_is_more = 1; 81 else { 82 s = lgetenv("LESS_IS_MORE"); 83 if (s != NULL && *s != '\0') 84 less_is_more = 1; 85 } 86 87 secure = 0; 88 s = lgetenv("LESSSECURE"); 89 if (s != NULL && *s != '\0') 90 secure = 1; 91 92 if (secure) { 93 if (pledge("stdio rpath tty", NULL) == -1) { 94 perror("pledge"); 95 exit(1); 96 } 97 } else { 98 if (pledge("stdio rpath wpath cpath fattr proc exec tty", NULL) == -1) { 99 perror("pledge"); 100 exit(1); 101 } 102 } 103 104 /* 105 * Process command line arguments and LESS environment arguments. 106 * Command line arguments override environment arguments. 107 */ 108 is_tty = isatty(1); 109 get_term(); 110 init_cmds(); 111 init_charset(); 112 init_line(); 113 init_cmdhist(); 114 init_option(); 115 init_search(); 116 117 118 init_prompt(); 119 120 if (less_is_more) { 121 /* this is specified by XPG */ 122 quit_at_eof = OPT_ON; 123 124 /* more users don't like the warning */ 125 know_dumb = OPT_ON; 126 127 /* default prompt is medium */ 128 pr_type = OPT_ON; 129 130 /* do not highlight search terms */ 131 hilite_search = OPT_OFF; 132 133 /* do not set init strings to terminal */ 134 no_init = OPT_ON; 135 136 /* repaint from top of screen */ 137 top_scroll = OPT_OFF; 138 } 139 140 s = lgetenv(less_is_more ? "MORE" : "LESS"); 141 if (s != NULL) 142 scan_option(estrdup(s), 1); 143 144 #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 145 while (argc > 0 && (isoptstring(*argv) || isoptpending())) { 146 s = *argv++; 147 argc--; 148 if (strcmp(s, "--") == 0) 149 break; 150 scan_option(s, 0); 151 } 152 #undef isoptstring 153 154 if (isoptpending()) { 155 /* 156 * Last command line option was a flag requiring a 157 * following string, but there was no following string. 158 */ 159 nopendopt(); 160 quit(QUIT_OK); 161 } 162 163 if (errmsgs) { 164 quit(QUIT_ERROR); 165 } 166 if (less_is_more && quit_at_eof == OPT_ONPLUS) { 167 extern int no_init; 168 no_init = OPT_ON; 169 } 170 if (less_is_more && pr_type == OPT_ONPLUS) { 171 extern int quiet; 172 quiet = VERY_QUIET; 173 } 174 175 editor = lgetenv("VISUAL"); 176 if (editor == NULL || *editor == '\0') { 177 editor = lgetenv("EDITOR"); 178 if (editor == NULL || *editor == '\0') 179 editor = EDIT_PGM; 180 } 181 editproto = lgetenv("LESSEDIT"); 182 if (editproto == NULL || *editproto == '\0') 183 editproto = "%E ?lm+%lm. %f"; 184 185 /* 186 * Call get_ifile with all the command line filenames 187 * to "register" them with the ifile system. 188 */ 189 ifile = NULL; 190 if (dohelp) 191 ifile = get_ifile(helpfile(), ifile); 192 while (argc-- > 0) { 193 char *filename; 194 filename = shell_quote(*argv); 195 if (filename == NULL) 196 filename = *argv; 197 argv++; 198 (void) get_ifile(filename, ifile); 199 ifile = prev_ifile(NULL); 200 free(filename); 201 } 202 /* 203 * Set up terminal, etc. 204 */ 205 if (!is_tty) { 206 /* 207 * Output is not a tty. 208 * Just copy the input file(s) to output. 209 */ 210 if (nifile() == 0) { 211 if (edit_stdin() == 0) 212 cat_file(); 213 } else if (edit_first() == 0) { 214 do { 215 cat_file(); 216 } while (edit_next(1) == 0); 217 } 218 quit(QUIT_OK); 219 } 220 221 if (missing_cap && !know_dumb) 222 error("WARNING: terminal is not fully functional", NULL); 223 init_mark(); 224 open_getchr(); 225 226 if (secure) 227 if (pledge("stdio rpath tty", NULL) == -1) { 228 perror("pledge"); 229 exit(1); 230 } 231 232 raw_mode(1); 233 init_signals(1); 234 235 /* 236 * Select the first file to examine. 237 */ 238 if (tagoption != NULL || strcmp(tags, "-") == 0) { 239 /* 240 * A -t option was given. 241 * Verify that no filenames were also given. 242 * Edit the file selected by the "tags" search, 243 * and search for the proper line in the file. 244 */ 245 if (nifile() > 0) { 246 error("No filenames allowed with -t option", NULL); 247 quit(QUIT_ERROR); 248 } 249 findtag(tagoption); 250 if (edit_tagfile()) /* Edit file which contains the tag */ 251 quit(QUIT_ERROR); 252 /* 253 * Search for the line which contains the tag. 254 * Set up initial_scrpos so we display that line. 255 */ 256 initial_scrpos.pos = tagsearch(); 257 if (initial_scrpos.pos == -1) 258 quit(QUIT_ERROR); 259 initial_scrpos.ln = jump_sline; 260 } else if (nifile() == 0) { 261 if (edit_stdin()) /* Edit standard input */ 262 quit(QUIT_ERROR); 263 } else { 264 if (edit_first()) /* Edit first valid file in cmd line */ 265 quit(QUIT_ERROR); 266 } 267 268 init(); 269 commands(); 270 quit(QUIT_OK); 271 return (0); 272 } 273 274 /* 275 * Allocate memory. 276 * Like calloc(), but never returns an error (NULL). 277 */ 278 void * 279 ecalloc(int count, unsigned int size) 280 { 281 void *p; 282 283 p = calloc(count, size); 284 if (p != NULL) 285 return (p); 286 error("Cannot allocate memory", NULL); 287 quit(QUIT_ERROR); 288 return (NULL); 289 } 290 291 char * 292 easprintf(const char *fmt, ...) 293 { 294 char *p = NULL; 295 int rv; 296 va_list ap; 297 298 va_start(ap, fmt); 299 rv = vasprintf(&p, fmt, ap); 300 va_end(ap); 301 302 if (rv == -1) { 303 error("Cannot allocate memory", NULL); 304 quit(QUIT_ERROR); 305 } 306 return (p); 307 } 308 309 char * 310 estrdup(const char *str) 311 { 312 char *n; 313 314 n = strdup(str); 315 if (n == NULL) { 316 error("Cannot allocate memory", NULL); 317 quit(QUIT_ERROR); 318 } 319 return (n); 320 } 321 322 /* 323 * Skip leading spaces in a string. 324 */ 325 char * 326 skipsp(char *s) 327 { 328 while (*s == ' ' || *s == '\t') 329 s++; 330 return (s); 331 } 332 333 /* 334 * See how many characters of two strings are identical. 335 * If uppercase is true, the first string must begin with an uppercase 336 * character; the remainder of the first string may be either case. 337 */ 338 int 339 sprefix(char *ps, char *s, int uppercase) 340 { 341 int c; 342 int sc; 343 int len = 0; 344 345 for (; *s != '\0'; s++, ps++) { 346 c = *ps; 347 if (uppercase) { 348 if (len == 0 && islower(c)) 349 return (-1); 350 c = tolower(c); 351 } 352 sc = *s; 353 if (len > 0) 354 sc = tolower(sc); 355 if (c != sc) 356 break; 357 len++; 358 } 359 return (len); 360 } 361 362 /* 363 * Exit the program. 364 */ 365 void 366 quit(int status) 367 { 368 static int save_status; 369 370 /* 371 * Put cursor at bottom left corner, clear the line, 372 * reset the terminal modes, and exit. 373 */ 374 if (status < 0) 375 status = save_status; 376 else 377 save_status = status; 378 quitting = 1; 379 edit(NULL); 380 if (!secure) 381 save_cmdhist(); 382 if (any_display && is_tty) 383 clear_bot(); 384 deinit(); 385 flush(1); 386 raw_mode(0); 387 exit(status); 388 } 389 390 char * 391 helpfile(void) 392 { 393 return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help"); 394 } 395