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 if (strcmp(argv[0], "--") == 0) { 126 argv++; 127 argc--; 128 break; 129 } 130 scan_option(*argv++); 131 } 132 #undef isoptstring 133 134 if (isoptpending()) 135 { 136 /* 137 * Last command line option was a flag requiring a 138 * following string, but there was no following string. 139 */ 140 nopendopt(); 141 quit(QUIT_OK); 142 } 143 144 #if EDITOR 145 editor = getenv("VISUAL"); 146 if (editor == NULL || *editor == '\0') 147 { 148 editor = getenv("EDITOR"); 149 if (editor == NULL || *editor == '\0') 150 editor = EDIT_PGM; 151 } 152 editproto = getenv("LESSEDIT"); 153 if (editproto == NULL || *editproto == '\0') 154 editproto = "%E ?lm+%lm. %f"; 155 #endif 156 157 /* 158 * Call get_ifile with all the command line filenames 159 * to "register" them with the ifile system. 160 */ 161 ifile = NULL_IFILE; 162 while (--argc >= 0) 163 { 164 #if MSOFTC || OS2 165 /* 166 * Because the "shell" doesn't expand filename patterns, 167 * treat each argument as a filename pattern rather than 168 * a single filename. 169 * Expand the pattern and iterate over the expanded list. 170 */ 171 struct textlist tlist; 172 char *gfilename; 173 char *filename; 174 175 gfilename = glob(*argv++); 176 init_textlist(&tlist, gfilename); 177 filename = NULL; 178 while ((filename = forw_textlist(&tlist, filename)) != NULL) 179 ifile = get_ifile(filename, ifile); 180 free(gfilename); 181 #else 182 ifile = get_ifile(*argv++, ifile); 183 #endif 184 } 185 /* 186 * Set up terminal, etc. 187 */ 188 is_tty = isatty(1); 189 if (!is_tty) 190 { 191 /* 192 * Output is not a tty. 193 * Just copy the input file(s) to output. 194 */ 195 if (nifile() == 0) 196 { 197 if (edit_stdin() == 0) 198 cat_file(); 199 } else if (edit_first() == 0) 200 { 201 do { 202 cat_file(); 203 } while (edit_next(1) == 0); 204 } 205 quit(QUIT_OK); 206 } 207 208 init_mark(); 209 raw_mode(1); 210 open_getchr(); 211 init_signals(1); 212 213 /* 214 * Select the first file to examine. 215 */ 216 #if TAGS 217 if (tagoption != NULL) 218 { 219 /* 220 * A -t option was given. 221 * Verify that no filenames were also given. 222 * Edit the file selected by the "tags" search, 223 * and search for the proper line in the file. 224 */ 225 if (nifile() > 0) 226 { 227 error("No filenames allowed with -t option", NULL_PARG); 228 quit(QUIT_ERROR); 229 } 230 findtag(tagoption); 231 if (tagfile == NULL) 232 quit(QUIT_ERROR); 233 if (edit(tagfile)) /* Edit file which contains the tag */ 234 quit(QUIT_ERROR); 235 /* 236 * Search for the line which contains the tag. 237 * Set up initial_scrpos so we display that line. 238 */ 239 initial_scrpos.pos = tagsearch(); 240 if (initial_scrpos.pos == NULL_POSITION) 241 quit(QUIT_ERROR); 242 initial_scrpos.ln = jump_sline; 243 } else 244 #endif 245 if (nifile() == 0) 246 { 247 if (edit_stdin()) /* Edit standard input */ 248 quit(QUIT_ERROR); 249 } else 250 { 251 if (edit_first()) /* Edit first valid file in cmd line */ 252 quit(QUIT_ERROR); 253 } 254 255 init(); 256 commands(); 257 quit(QUIT_OK); 258 /*NOTREACHED*/ 259 } 260 261 /* 262 * Copy a string, truncating to the specified length if necessary. 263 * Unlike strncpy(), the resulting string is guaranteed to be null-terminated. 264 */ 265 public void 266 strtcpy(to, from, len) 267 char *to; 268 char *from; 269 unsigned int len; 270 { 271 strncpy(to, from, len); 272 to[len-1] = '\0'; 273 } 274 275 /* 276 * Copy a string to a "safe" place 277 * (that is, to a buffer allocated by calloc). 278 */ 279 public char * 280 save(s) 281 char *s; 282 { 283 register char *p; 284 285 p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 286 strcpy(p, s); 287 return (p); 288 } 289 290 /* 291 * Allocate memory. 292 * Like calloc(), but never returns an error (NULL). 293 */ 294 public VOID_POINTER 295 ecalloc(count, size) 296 int count; 297 unsigned int size; 298 { 299 register VOID_POINTER p; 300 301 p = (VOID_POINTER) calloc(count, size); 302 if (p != NULL) 303 return (p); 304 error("Cannot allocate memory", NULL_PARG); 305 quit(QUIT_ERROR); 306 /*NOTREACHED*/ 307 } 308 309 /* 310 * Skip leading spaces in a string. 311 */ 312 public char * 313 skipsp(s) 314 register char *s; 315 { 316 while (*s == ' ' || *s == '\t') 317 s++; 318 return (s); 319 } 320 321 /* 322 * Exit the program. 323 */ 324 public void 325 quit(status) 326 int status; 327 { 328 static int save_status; 329 330 /* 331 * Put cursor at bottom left corner, clear the line, 332 * reset the terminal modes, and exit. 333 */ 334 if (status < 0) 335 status = save_status; 336 else 337 save_status = status; 338 quitting = 1; 339 edit((char*)NULL); 340 if (is_tty && any_display) 341 clear_bot(); 342 deinit(); 343 flush(); 344 raw_mode(0); 345 #if MSOFTC 346 /* 347 * If we don't close 2, we get some garbage from 348 * 2's buffer when it flushes automatically. 349 * I cannot track this one down RB 350 * The same bug shows up if we use ^C^C to abort. 351 */ 352 close(2); 353 #endif 354 exit(status); 355 } 356