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