1 /* 2 * Copyright (c) 1988 Mark Nudleman 3 * Copyright (c) 1988, 1993 4 * Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 char copyright[] = 11 "@(#) Copyright (c) 1988 Mark Nudleman.\n\ 12 @(#) Copyright (c) 1988, 1993 13 Regents of the University of California. All rights reserved.\n"; 14 #endif /* not lint */ 15 16 #ifndef lint 17 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/07/93"; 18 #endif /* not lint */ 19 20 /* 21 * Entry point, initialization, miscellaneous routines. 22 */ 23 24 #include <sys/types.h> 25 #include <sys/file.h> 26 #include <stdio.h> 27 #include <less.h> 28 29 int ispipe; 30 int new_file; 31 int is_tty; 32 char *current_file, *previous_file, *current_name, *next_name; 33 off_t prev_pos; 34 int any_display; 35 int scroll; 36 int ac; 37 char **av; 38 int curr_ac; 39 int quitting; 40 41 extern int file; 42 extern int cbufs; 43 extern int errmsgs; 44 45 extern char *tagfile; 46 extern int tagoption; 47 48 /* 49 * Edit a new file. 50 * Filename "-" means standard input. 51 * No filename means the "current" file, from the command line. 52 */ 53 edit(filename) 54 register char *filename; 55 { 56 extern int errno; 57 register int f; 58 register char *m; 59 off_t initial_pos, position(); 60 static int didpipe; 61 char message[100], *p; 62 char *rindex(), *strerror(), *save(), *bad_file(); 63 64 initial_pos = NULL_POSITION; 65 if (filename == NULL || *filename == '\0') { 66 if (curr_ac >= ac) { 67 error("No current file"); 68 return(0); 69 } 70 filename = save(av[curr_ac]); 71 } 72 else if (strcmp(filename, "#") == 0) { 73 if (*previous_file == '\0') { 74 error("no previous file"); 75 return(0); 76 } 77 filename = save(previous_file); 78 initial_pos = prev_pos; 79 } else 80 filename = save(filename); 81 82 /* use standard input. */ 83 if (!strcmp(filename, "-")) { 84 if (didpipe) { 85 error("Can view standard input only once"); 86 return(0); 87 } 88 f = 0; 89 } 90 else if ((m = bad_file(filename, message, sizeof(message))) != NULL) { 91 error(m); 92 free(filename); 93 return(0); 94 } 95 else if ((f = open(filename, O_RDONLY, 0)) < 0) { 96 (void)sprintf(message, "%s: %s", filename, strerror(errno)); 97 error(message); 98 free(filename); 99 return(0); 100 } 101 102 if (isatty(f)) { 103 /* 104 * Not really necessary to call this an error, 105 * but if the control terminal (for commands) 106 * and the input file (for data) are the same, 107 * we get weird results at best. 108 */ 109 error("Can't take input from a terminal"); 110 if (f > 0) 111 (void)close(f); 112 (void)free(filename); 113 return(0); 114 } 115 116 /* 117 * We are now committed to using the new file. 118 * Close the current input file and set up to use the new one. 119 */ 120 if (file > 0) 121 (void)close(file); 122 new_file = 1; 123 if (previous_file != NULL) 124 free(previous_file); 125 previous_file = current_file; 126 current_file = filename; 127 pos_clear(); 128 prev_pos = position(TOP); 129 ispipe = (f == 0); 130 if (ispipe) { 131 didpipe = 1; 132 current_name = "stdin"; 133 } else 134 current_name = (p = rindex(filename, '/')) ? p + 1 : filename; 135 if (curr_ac >= ac) 136 next_name = NULL; 137 else 138 next_name = av[curr_ac + 1]; 139 file = f; 140 ch_init(cbufs, 0); 141 init_mark(); 142 143 if (is_tty) { 144 int no_display = !any_display; 145 any_display = 1; 146 if (no_display && errmsgs > 0) { 147 /* 148 * We displayed some messages on error output 149 * (file descriptor 2; see error() function). 150 * Before erasing the screen contents, 151 * display the file name and wait for a keystroke. 152 */ 153 error(filename); 154 } 155 /* 156 * Indicate there is nothing displayed yet. 157 */ 158 if (initial_pos != NULL_POSITION) 159 jump_loc(initial_pos); 160 clr_linenum(); 161 } 162 return(1); 163 } 164 165 /* 166 * Edit the next file in the command line list. 167 */ 168 next_file(n) 169 int n; 170 { 171 extern int quit_at_eof; 172 off_t position(); 173 174 if (curr_ac + n >= ac) { 175 if (quit_at_eof || position(TOP) == NULL_POSITION) 176 quit(); 177 error("No (N-th) next file"); 178 } 179 else 180 (void)edit(av[curr_ac += n]); 181 } 182 183 /* 184 * Edit the previous file in the command line list. 185 */ 186 prev_file(n) 187 int n; 188 { 189 if (curr_ac - n < 0) 190 error("No (N-th) previous file"); 191 else 192 (void)edit(av[curr_ac -= n]); 193 } 194 195 /* 196 * copy a file directly to standard output; used if stdout is not a tty. 197 * the only processing is to squeeze multiple blank input lines. 198 */ 199 static 200 cat_file() 201 { 202 extern int squeeze; 203 register int c, empty; 204 205 if (squeeze) { 206 empty = 0; 207 while ((c = ch_forw_get()) != EOI) 208 if (c != '\n') { 209 putchr(c); 210 empty = 0; 211 } 212 else if (empty < 2) { 213 putchr(c); 214 ++empty; 215 } 216 } 217 else while ((c = ch_forw_get()) != EOI) 218 putchr(c); 219 flush(); 220 } 221 222 main(argc, argv) 223 int argc; 224 char **argv; 225 { 226 int envargc, argcnt; 227 char *envargv[2], *getenv(); 228 229 /* 230 * Process command line arguments and MORE environment arguments. 231 * Command line arguments override environment arguments. 232 */ 233 if (envargv[1] = getenv("MORE")) { 234 envargc = 2; 235 envargv[0] = "more"; 236 envargv[2] = NULL; 237 (void)option(envargc, envargv); 238 } 239 argcnt = option(argc, argv); 240 argv += argcnt; 241 argc -= argcnt; 242 243 /* 244 * Set up list of files to be examined. 245 */ 246 ac = argc; 247 av = argv; 248 curr_ac = 0; 249 250 /* 251 * Set up terminal, etc. 252 */ 253 is_tty = isatty(1); 254 if (!is_tty) { 255 /* 256 * Output is not a tty. 257 * Just copy the input file(s) to output. 258 */ 259 if (ac < 1) { 260 (void)edit("-"); 261 cat_file(); 262 } else { 263 do { 264 (void)edit((char *)NULL); 265 if (file >= 0) 266 cat_file(); 267 } while (++curr_ac < ac); 268 } 269 exit(0); 270 } 271 272 raw_mode(1); 273 get_term(); 274 open_getchr(); 275 init(); 276 init_signals(1); 277 278 /* select the first file to examine. */ 279 if (tagoption) { 280 /* 281 * A -t option was given; edit the file selected by the 282 * "tags" search, and search for the proper line in the file. 283 */ 284 if (!tagfile || !edit(tagfile) || tagsearch()) 285 quit(); 286 } 287 else if (ac < 1) 288 (void)edit("-"); /* Standard input */ 289 else { 290 /* 291 * Try all the files named as command arguments. 292 * We are simply looking for one which can be 293 * opened without error. 294 */ 295 do { 296 (void)edit((char *)NULL); 297 } while (file < 0 && ++curr_ac < ac); 298 } 299 300 if (file >= 0) 301 commands(); 302 quit(); 303 /*NOTREACHED*/ 304 } 305 306 /* 307 * Copy a string to a "safe" place 308 * (that is, to a buffer allocated by malloc). 309 */ 310 char * 311 save(s) 312 char *s; 313 { 314 char *p, *strcpy(), *malloc(); 315 316 p = malloc((u_int)strlen(s)+1); 317 if (p == NULL) 318 { 319 error("cannot allocate memory"); 320 quit(); 321 } 322 return(strcpy(p, s)); 323 } 324 325 /* 326 * Exit the program. 327 */ 328 quit() 329 { 330 /* 331 * Put cursor at bottom left corner, clear the line, 332 * reset the terminal modes, and exit. 333 */ 334 quitting = 1; 335 lower_left(); 336 clear_eol(); 337 deinit(); 338 flush(); 339 raw_mode(0); 340 exit(0); 341 } 342