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