1 /* 2 * Copyright (C) 1984-2014 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 char *env = (char *) ecalloc(strlen(drive) + 98 strlen(path) + 6, sizeof(char)); 99 strcpy(env, "HOME="); 100 strcat(env, drive); 101 strcat(env, path); 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 s = lgetenv(less_is_more ? "MORE" : "LESS"); 136 if (s != NULL) 137 scan_option(save(s)); 138 139 #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 140 while (argc > 0 && (isoptstring(*argv) || isoptpending())) 141 { 142 s = *argv++; 143 argc--; 144 if (strcmp(s, "--") == 0) 145 break; 146 scan_option(s); 147 } 148 #undef isoptstring 149 150 if (isoptpending()) 151 { 152 /* 153 * Last command line option was a flag requiring a 154 * following string, but there was no following string. 155 */ 156 nopendopt(); 157 quit(QUIT_OK); 158 } 159 160 #if EDITOR 161 editor = lgetenv("VISUAL"); 162 if (editor == NULL || *editor == '\0') 163 { 164 editor = lgetenv("EDITOR"); 165 if (editor == NULL || *editor == '\0') 166 editor = EDIT_PGM; 167 } 168 editproto = lgetenv("LESSEDIT"); 169 if (editproto == NULL || *editproto == '\0') 170 editproto = "%E ?lm+%lm. %f"; 171 #endif 172 173 /* 174 * Call get_ifile with all the command line filenames 175 * to "register" them with the ifile system. 176 */ 177 ifile = NULL_IFILE; 178 if (dohelp) 179 ifile = get_ifile(FAKE_HELPFILE, ifile); 180 while (argc-- > 0) 181 { 182 char *filename; 183 #if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 184 /* 185 * Because the "shell" doesn't expand filename patterns, 186 * treat each argument as a filename pattern rather than 187 * a single filename. 188 * Expand the pattern and iterate over the expanded list. 189 */ 190 struct textlist tlist; 191 char *gfilename; 192 193 gfilename = lglob(*argv++); 194 init_textlist(&tlist, gfilename); 195 filename = NULL; 196 while ((filename = forw_textlist(&tlist, filename)) != NULL) 197 { 198 (void) get_ifile(filename, ifile); 199 ifile = prev_ifile(NULL_IFILE); 200 } 201 free(gfilename); 202 #else 203 filename = shell_quote(*argv); 204 if (filename == NULL) 205 filename = *argv; 206 argv++; 207 (void) get_ifile(filename, ifile); 208 ifile = prev_ifile(NULL_IFILE); 209 free(filename); 210 #endif 211 } 212 /* 213 * Set up terminal, etc. 214 */ 215 if (!is_tty) 216 { 217 /* 218 * Output is not a tty. 219 * Just copy the input file(s) to output. 220 */ 221 SET_BINARY(1); 222 if (nifile() == 0) 223 { 224 if (edit_stdin() == 0) 225 cat_file(); 226 } else if (edit_first() == 0) 227 { 228 do { 229 cat_file(); 230 } while (edit_next(1) == 0); 231 } 232 quit(QUIT_OK); 233 } 234 235 if (missing_cap && !know_dumb) 236 error("WARNING: terminal is not fully functional", NULL_PARG); 237 init_mark(); 238 open_getchr(); 239 raw_mode(1); 240 init_signals(1); 241 242 /* 243 * Select the first file to examine. 244 */ 245 #if TAGS 246 if (tagoption != NULL || strcmp(tags, "-") == 0) 247 { 248 /* 249 * A -t option was given. 250 * Verify that no filenames were also given. 251 * Edit the file selected by the "tags" search, 252 * and search for the proper line in the file. 253 */ 254 if (nifile() > 0) 255 { 256 error("No filenames allowed with -t option", NULL_PARG); 257 quit(QUIT_ERROR); 258 } 259 findtag(tagoption); 260 if (edit_tagfile()) /* Edit file which contains the tag */ 261 quit(QUIT_ERROR); 262 /* 263 * Search for the line which contains the tag. 264 * Set up initial_scrpos so we display that line. 265 */ 266 initial_scrpos.pos = tagsearch(); 267 if (initial_scrpos.pos == NULL_POSITION) 268 quit(QUIT_ERROR); 269 initial_scrpos.ln = jump_sline; 270 } else 271 #endif 272 if (nifile() == 0) 273 { 274 if (edit_stdin()) /* Edit standard input */ 275 quit(QUIT_ERROR); 276 } else 277 { 278 if (edit_first()) /* Edit first valid file in cmd line */ 279 quit(QUIT_ERROR); 280 } 281 282 init(); 283 commands(); 284 quit(QUIT_OK); 285 /*NOTREACHED*/ 286 return (0); 287 } 288 289 /* 290 * Copy a string to a "safe" place 291 * (that is, to a buffer allocated by calloc). 292 */ 293 public char * 294 save(s) 295 char *s; 296 { 297 register char *p; 298 299 p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 300 strcpy(p, s); 301 return (p); 302 } 303 304 /* 305 * Allocate memory. 306 * Like calloc(), but never returns an error (NULL). 307 */ 308 public VOID_POINTER 309 ecalloc(count, size) 310 int count; 311 unsigned int size; 312 { 313 register VOID_POINTER p; 314 315 p = (VOID_POINTER) calloc(count, size); 316 if (p != NULL) 317 return (p); 318 error("Cannot allocate memory", NULL_PARG); 319 quit(QUIT_ERROR); 320 /*NOTREACHED*/ 321 return (NULL); 322 } 323 324 /* 325 * Skip leading spaces in a string. 326 */ 327 public char * 328 skipsp(s) 329 register char *s; 330 { 331 while (*s == ' ' || *s == '\t') 332 s++; 333 return (s); 334 } 335 336 /* 337 * See how many characters of two strings are identical. 338 * If uppercase is true, the first string must begin with an uppercase 339 * character; the remainder of the first string may be either case. 340 */ 341 public int 342 sprefix(ps, s, uppercase) 343 char *ps; 344 char *s; 345 int uppercase; 346 { 347 register int c; 348 register int sc; 349 register int len = 0; 350 351 for ( ; *s != '\0'; s++, ps++) 352 { 353 c = *ps; 354 if (uppercase) 355 { 356 if (len == 0 && ASCII_IS_LOWER(c)) 357 return (-1); 358 if (ASCII_IS_UPPER(c)) 359 c = ASCII_TO_LOWER(c); 360 } 361 sc = *s; 362 if (len > 0 && ASCII_IS_UPPER(sc)) 363 sc = ASCII_TO_LOWER(sc); 364 if (c != sc) 365 break; 366 len++; 367 } 368 return (len); 369 } 370 371 /* 372 * Exit the program. 373 */ 374 public void 375 quit(status) 376 int status; 377 { 378 static int save_status; 379 380 /* 381 * Put cursor at bottom left corner, clear the line, 382 * reset the terminal modes, and exit. 383 */ 384 if (status < 0) 385 status = save_status; 386 else 387 save_status = status; 388 quitting = 1; 389 edit((char*)NULL); 390 save_cmdhist(); 391 if (any_display && is_tty) 392 clear_bot(); 393 deinit(); 394 flush(); 395 raw_mode(0); 396 #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 397 /* 398 * If we don't close 2, we get some garbage from 399 * 2's buffer when it flushes automatically. 400 * I cannot track this one down RB 401 * The same bug shows up if we use ^C^C to abort. 402 */ 403 close(2); 404 #endif 405 #ifdef WIN32 406 SetConsoleTitle(consoleTitle); 407 #endif 408 close_getchr(); 409 exit(status); 410 } 411