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