1 /* 2 * Copyright (C) 1984-2012 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 * Entry point, initialization, miscellaneous routines. 13 */ 14 15 #include "less.h" 16 #if MSDOS_COMPILER==WIN32C 17 #include <windows.h> 18 #endif 19 20 public char * every_first_cmd = NULL; 21 public int new_file; 22 public int is_tty; 23 public IFILE curr_ifile = NULL_IFILE; 24 public IFILE old_ifile = NULL_IFILE; 25 public struct scrpos initial_scrpos; 26 public int any_display = FALSE; 27 public POSITION start_attnpos = NULL_POSITION; 28 public POSITION end_attnpos = NULL_POSITION; 29 public int wscroll; 30 public char * progname; 31 public int quitting; 32 public int secure; 33 public int dohelp; 34 35 #if LOGFILE 36 public int logfile = -1; 37 public int force_logfile = FALSE; 38 public char * namelogfile = NULL; 39 #endif 40 41 #if EDITOR 42 public char * editor; 43 public char * editproto; 44 #endif 45 46 #if TAGS 47 extern char * tags; 48 extern char * tagoption; 49 extern int jump_sline; 50 #endif 51 52 #ifdef WIN32 53 static char consoleTitle[256]; 54 #endif 55 56 extern int less_is_more; 57 extern int missing_cap; 58 extern int know_dumb; 59 extern int pr_type; 60 61 62 /* 63 * Entry point. 64 */ 65 int 66 main(argc, argv) 67 int argc; 68 char *argv[]; 69 { 70 IFILE ifile; 71 char *s; 72 73 #ifdef __EMX__ 74 _response(&argc, &argv); 75 _wildcard(&argc, &argv); 76 #endif 77 78 progname = *argv++; 79 argc--; 80 81 secure = 0; 82 s = lgetenv("LESSSECURE"); 83 if (s != NULL && *s != '\0') 84 secure = 1; 85 86 #ifdef WIN32 87 if (getenv("HOME") == NULL) 88 { 89 /* 90 * If there is no HOME environment variable, 91 * try the concatenation of HOMEDRIVE + HOMEPATH. 92 */ 93 char *drive = getenv("HOMEDRIVE"); 94 char *path = getenv("HOMEPATH"); 95 if (drive != NULL && path != NULL) 96 { 97 size_t len = strlen(drive) + strlen(path) + 6; 98 char *env = (char *) ecalloc(len, sizeof(char)); 99 strlcpy(env, "HOME=", len); 100 strlcat(env, drive, len); 101 strlcat(env, path, len); 102 putenv(env); 103 } 104 } 105 GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char)); 106 #endif /* WIN32 */ 107 108 /* 109 * Process command line arguments and LESS environment arguments. 110 * Command line arguments override environment arguments. 111 */ 112 is_tty = isatty(1); 113 get_term(); 114 init_cmds(); 115 init_charset(); 116 init_line(); 117 init_cmdhist(); 118 init_option(); 119 init_search(); 120 121 /* 122 * If the name of the executable program is "more", 123 * act like LESS_IS_MORE is set. 124 */ 125 for (s = progname + strlen(progname); s > progname; s--) 126 { 127 if (s[-1] == PATHNAME_SEP[0]) 128 break; 129 } 130 if (strcmp(s, "more") == 0) 131 less_is_more = 1; 132 133 init_prompt(); 134 135 if (less_is_more) { 136 scan_option("-G"); 137 scan_option("-L"); 138 scan_option("-X"); 139 scan_option("-c"); 140 } 141 142 s = lgetenv(less_is_more ? "MORE" : "LESS"); 143 if (s != NULL) 144 scan_option(save(s)); 145 146 #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 147 while (argc > 0 && (isoptstring(*argv) || isoptpending())) 148 { 149 s = *argv++; 150 argc--; 151 if (strcmp(s, "--") == 0) 152 break; 153 scan_option(s); 154 } 155 #undef isoptstring 156 157 if (isoptpending()) 158 { 159 /* 160 * Last command line option was a flag requiring a 161 * following string, but there was no following string. 162 */ 163 nopendopt(); 164 quit(QUIT_OK); 165 } 166 167 #if EDITOR 168 editor = lgetenv("VISUAL"); 169 if (editor == NULL || *editor == '\0') 170 { 171 editor = lgetenv("EDITOR"); 172 if (editor == NULL || *editor == '\0') 173 editor = EDIT_PGM; 174 } 175 editproto = lgetenv("LESSEDIT"); 176 if (editproto == NULL || *editproto == '\0') 177 editproto = "%E ?lm+%lm. %f"; 178 #endif 179 180 /* 181 * Call get_ifile with all the command line filenames 182 * to "register" them with the ifile system. 183 */ 184 ifile = NULL_IFILE; 185 #if !SMALL 186 if (dohelp) 187 ifile = get_ifile(helpfile(), ifile); 188 #endif /* !SMALL */ 189 while (argc-- > 0) 190 { 191 char *filename; 192 #if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 193 /* 194 * Because the "shell" doesn't expand filename patterns, 195 * treat each argument as a filename pattern rather than 196 * a single filename. 197 * Expand the pattern and iterate over the expanded list. 198 */ 199 struct textlist tlist; 200 char *gfilename; 201 202 gfilename = lglob(*argv++); 203 init_textlist(&tlist, gfilename); 204 filename = NULL; 205 while ((filename = forw_textlist(&tlist, filename)) != NULL) 206 { 207 (void) get_ifile(filename, ifile); 208 ifile = prev_ifile(NULL_IFILE); 209 } 210 free(gfilename); 211 #else 212 filename = shell_quote(*argv); 213 if (filename == NULL) 214 filename = *argv; 215 argv++; 216 (void) get_ifile(filename, ifile); 217 ifile = prev_ifile(NULL_IFILE); 218 free(filename); 219 #endif 220 } 221 /* 222 * Set up terminal, etc. 223 */ 224 if (!is_tty) 225 { 226 /* 227 * Output is not a tty. 228 * Just copy the input file(s) to output. 229 */ 230 SET_BINARY(1); 231 if (nifile() == 0) 232 { 233 if (edit_stdin() == 0) 234 cat_file(); 235 } else if (edit_first() == 0) 236 { 237 do { 238 cat_file(); 239 } while (edit_next(1) == 0); 240 } 241 quit(QUIT_OK); 242 } 243 244 if (missing_cap && !know_dumb && !less_is_more) 245 error("WARNING: terminal is not fully functional", NULL_PARG); 246 init_mark(); 247 open_getchr(); 248 raw_mode(1); 249 init_signals(1); 250 251 /* 252 * Select the first file to examine. 253 */ 254 #if TAGS 255 if (tagoption != NULL || strcmp(tags, "-") == 0) 256 { 257 /* 258 * A -t option was given. 259 * Verify that no filenames were also given. 260 * Edit the file selected by the "tags" search, 261 * and search for the proper line in the file. 262 */ 263 if (nifile() > 0) 264 { 265 error("No filenames allowed with -t option", NULL_PARG); 266 quit(QUIT_ERROR); 267 } 268 findtag(tagoption); 269 if (edit_tagfile()) /* Edit file which contains the tag */ 270 quit(QUIT_ERROR); 271 /* 272 * Search for the line which contains the tag. 273 * Set up initial_scrpos so we display that line. 274 */ 275 initial_scrpos.pos = tagsearch(); 276 if (initial_scrpos.pos == NULL_POSITION) 277 quit(QUIT_ERROR); 278 initial_scrpos.ln = jump_sline; 279 } else 280 #endif 281 if (nifile() == 0) 282 { 283 if (edit_stdin()) /* Edit standard input */ 284 quit(QUIT_ERROR); 285 } else 286 { 287 if (edit_first()) /* Edit first valid file in cmd line */ 288 quit(QUIT_ERROR); 289 } 290 291 init(); 292 commands(); 293 quit(QUIT_OK); 294 /*NOTREACHED*/ 295 return (0); 296 } 297 298 /* 299 * Copy a string to a "safe" place 300 * (that is, to a buffer allocated by calloc). 301 */ 302 public char * 303 save(s) 304 char *s; 305 { 306 register char *p; 307 size_t len = strlen(s) + 1; 308 309 p = (char *) ecalloc(len, sizeof(char)); 310 strlcpy(p, s, len); 311 return (p); 312 } 313 314 /* 315 * Allocate memory. 316 * Like calloc(), but never returns an error (NULL). 317 */ 318 public VOID_POINTER 319 ecalloc(count, size) 320 int count; 321 unsigned int size; 322 { 323 register VOID_POINTER p; 324 325 p = (VOID_POINTER) calloc(count, size); 326 if (p != NULL) 327 return (p); 328 error("Cannot allocate memory", NULL_PARG); 329 quit(QUIT_ERROR); 330 /*NOTREACHED*/ 331 return (NULL); 332 } 333 334 /* 335 * Skip leading spaces in a string. 336 */ 337 public char * 338 skipsp(s) 339 register char *s; 340 { 341 while (*s == ' ' || *s == '\t') 342 s++; 343 return (s); 344 } 345 346 #if GNU_OPTIONS 347 /* 348 * See how many characters of two strings are identical. 349 * If uppercase is true, the first string must begin with an uppercase 350 * character; the remainder of the first string may be either case. 351 */ 352 public int 353 sprefix(ps, s, uppercase) 354 char *ps; 355 char *s; 356 int uppercase; 357 { 358 register int c; 359 register int sc; 360 register int len = 0; 361 362 for ( ; *s != '\0'; s++, ps++) 363 { 364 c = *ps; 365 if (uppercase) 366 { 367 if (len == 0 && ASCII_IS_LOWER(c)) 368 return (-1); 369 if (ASCII_IS_UPPER(c)) 370 c = ASCII_TO_LOWER(c); 371 } 372 sc = *s; 373 if (len > 0 && ASCII_IS_UPPER(sc)) 374 sc = ASCII_TO_LOWER(sc); 375 if (c != sc) 376 break; 377 len++; 378 } 379 return (len); 380 } 381 #endif /* GNU_OPTIONS */ 382 383 /* 384 * Exit the program. 385 */ 386 public void 387 quit(status) 388 int status; 389 { 390 static int save_status; 391 392 /* 393 * Put cursor at bottom left corner, clear the line, 394 * reset the terminal modes, and exit. 395 */ 396 if (status < 0) 397 status = save_status; 398 else 399 save_status = status; 400 quitting = 1; 401 edit((char*)NULL); 402 save_cmdhist(); 403 if (any_display && is_tty) 404 clear_bot(); 405 deinit(); 406 flush(); 407 raw_mode(0); 408 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 409 /* 410 * If we don't close 2, we get some garbage from 411 * 2's buffer when it flushes automatically. 412 * I cannot track this one down RB 413 * The same bug shows up if we use ^C^C to abort. 414 */ 415 close(2); 416 #endif 417 #ifdef WIN32 418 SetConsoleTitle(consoleTitle); 419 #endif 420 close_getchr(); 421 exit(status); 422 } 423 424 #if !SMALL 425 public char * 426 helpfile(void) 427 { 428 return (less_is_more ? HELPDIR "/more.help" : HELPDIR "/less.help"); 429 } 430 #endif /* !SMALL */ 431