1 /* 2 * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice in the documentation and/or other materials provided with 12 * the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 28 /* 29 * Entry point, initialization, miscellaneous routines. 30 */ 31 32 #include "less.h" 33 #include "position.h" 34 35 public char * every_first_cmd = NULL; 36 public int new_file; 37 public int is_tty; 38 public IFILE curr_ifile = NULL_IFILE; 39 public IFILE old_ifile = NULL_IFILE; 40 public struct scrpos initial_scrpos; 41 public int any_display = FALSE; 42 public int wscroll; 43 public char * progname; 44 public int quitting; 45 public int more_mode = 0; 46 47 extern int quit_at_eof; 48 extern int cbufs; 49 extern int errmsgs; 50 extern int screen_trashed; 51 extern int force_open; 52 53 #if LOGFILE 54 public int logfile = -1; 55 public int force_logfile = FALSE; 56 public char * namelogfile = NULL; 57 #endif 58 59 #if EDITOR 60 public char * editor; 61 public char * editproto; 62 #endif 63 64 #if TAGS 65 extern char * tagfile; 66 extern char * tagoption; 67 extern int jump_sline; 68 #endif 69 70 71 72 /* 73 * Entry point. 74 */ 75 int 76 main(argc, argv) 77 int argc; 78 char *argv[]; 79 { 80 IFILE ifile; 81 extern char *__progname; 82 83 #ifdef __EMX__ 84 _response(&argc, &argv); 85 _wildcard(&argc, &argv); 86 #endif 87 88 progname = *argv++; 89 90 /* 91 * Process command line arguments and LESS environment arguments. 92 * Command line arguments override environment arguments. 93 */ 94 if (strcmp(__progname, "more") == 0) 95 more_mode = 1; 96 97 get_term(); 98 init_cmds(); 99 init_prompt(); 100 init_charset(); 101 init_option(); 102 103 if (more_mode) { 104 scan_option("-E"); 105 scan_option("-m"); 106 scan_option("-G"); 107 scan_option(getenv("MORE")); 108 } else 109 scan_option(getenv("LESS")); 110 111 #if GNU_OPTIONS 112 /* 113 * Special case for "less --help" and "less --version". 114 */ 115 if (argc == 2) 116 { 117 if (strcmp(argv[0], "--help") == 0) 118 scan_option("-?"); 119 if (strcmp(argv[0], "--version") == 0) 120 scan_option("-V"); 121 } 122 #endif 123 #define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 124 while (--argc > 0 && (isoptstring(argv[0]) || isoptpending())) 125 scan_option(*argv++); 126 #undef isoptstring 127 128 if (isoptpending()) 129 { 130 /* 131 * Last command line option was a flag requiring a 132 * following string, but there was no following string. 133 */ 134 nopendopt(); 135 quit(QUIT_OK); 136 } 137 138 #if EDITOR 139 editor = getenv("VISUAL"); 140 if (editor == NULL || *editor == '\0') 141 { 142 editor = getenv("EDITOR"); 143 if (editor == NULL || *editor == '\0') 144 editor = EDIT_PGM; 145 } 146 editproto = getenv("LESSEDIT"); 147 if (editproto == NULL || *editproto == '\0') 148 editproto = "%E ?lm+%lm. %f"; 149 #endif 150 151 /* 152 * Call get_ifile with all the command line filenames 153 * to "register" them with the ifile system. 154 */ 155 ifile = NULL_IFILE; 156 while (--argc >= 0) 157 { 158 #if MSOFTC || OS2 159 /* 160 * Because the "shell" doesn't expand filename patterns, 161 * treat each argument as a filename pattern rather than 162 * a single filename. 163 * Expand the pattern and iterate over the expanded list. 164 */ 165 struct textlist tlist; 166 char *gfilename; 167 char *filename; 168 169 gfilename = glob(*argv++); 170 init_textlist(&tlist, gfilename); 171 filename = NULL; 172 while ((filename = forw_textlist(&tlist, filename)) != NULL) 173 ifile = get_ifile(filename, ifile); 174 free(gfilename); 175 #else 176 ifile = get_ifile(*argv++, ifile); 177 #endif 178 } 179 /* 180 * Set up terminal, etc. 181 */ 182 is_tty = isatty(1); 183 if (!is_tty) 184 { 185 /* 186 * Output is not a tty. 187 * Just copy the input file(s) to output. 188 */ 189 if (nifile() == 0) 190 { 191 if (edit_stdin() == 0) 192 cat_file(); 193 } else if (edit_first() == 0) 194 { 195 do { 196 cat_file(); 197 } while (edit_next(1) == 0); 198 } 199 quit(QUIT_OK); 200 } 201 202 init_mark(); 203 raw_mode(1); 204 open_getchr(); 205 init_signals(1); 206 207 /* 208 * Select the first file to examine. 209 */ 210 #if TAGS 211 if (tagoption != NULL) 212 { 213 /* 214 * A -t option was given. 215 * Verify that no filenames were also given. 216 * Edit the file selected by the "tags" search, 217 * and search for the proper line in the file. 218 */ 219 if (nifile() > 0) 220 { 221 error("No filenames allowed with -t option", NULL_PARG); 222 quit(QUIT_ERROR); 223 } 224 findtag(tagoption); 225 if (tagfile == NULL) 226 quit(QUIT_ERROR); 227 if (edit(tagfile)) /* Edit file which contains the tag */ 228 quit(QUIT_ERROR); 229 /* 230 * Search for the line which contains the tag. 231 * Set up initial_scrpos so we display that line. 232 */ 233 initial_scrpos.pos = tagsearch(); 234 if (initial_scrpos.pos == NULL_POSITION) 235 quit(QUIT_ERROR); 236 initial_scrpos.ln = jump_sline; 237 } else 238 #endif 239 if (nifile() == 0) 240 { 241 if (edit_stdin()) /* Edit standard input */ 242 quit(QUIT_ERROR); 243 } else 244 { 245 if (edit_first()) /* Edit first valid file in cmd line */ 246 quit(QUIT_ERROR); 247 } 248 249 init(); 250 commands(); 251 quit(QUIT_OK); 252 /*NOTREACHED*/ 253 } 254 255 /* 256 * Copy a string, truncating to the specified length if necessary. 257 * Unlike strncpy(), the resulting string is guaranteed to be null-terminated. 258 */ 259 public void 260 strtcpy(to, from, len) 261 char *to; 262 char *from; 263 unsigned int len; 264 { 265 strncpy(to, from, len); 266 to[len-1] = '\0'; 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 * Exit the program. 317 */ 318 public void 319 quit(status) 320 int status; 321 { 322 static int save_status; 323 324 /* 325 * Put cursor at bottom left corner, clear the line, 326 * reset the terminal modes, and exit. 327 */ 328 if (status < 0) 329 status = save_status; 330 else 331 save_status = status; 332 quitting = 1; 333 edit((char*)NULL); 334 if (is_tty && any_display) 335 clear_bot(); 336 deinit(); 337 flush(); 338 raw_mode(0); 339 #if MSOFTC 340 /* 341 * If we don't close 2, we get some garbage from 342 * 2's buffer when it flushes automatically. 343 * I cannot track this one down RB 344 * The same bug shows up if we use ^C^C to abort. 345 */ 346 close(2); 347 #endif 348 exit(status); 349 } 350