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