1*35209Sbostic /* 2*35209Sbostic * Copyright (c) 1988 Mark Nudleman 3*35209Sbostic * Copyright (c) 1988 Regents of the University of California. 4*35209Sbostic * All rights reserved. 5*35209Sbostic * 6*35209Sbostic * This code is derived from software contributed to Berkeley by 7*35209Sbostic * Mark Nudleman. 8*35209Sbostic * 9*35209Sbostic * Redistribution and use in source and binary forms are permitted 10*35209Sbostic * provided that the above copyright notice and this paragraph are 11*35209Sbostic * duplicated in all such forms and that any documentation, 12*35209Sbostic * advertising materials, and other materials related to such 13*35209Sbostic * distribution and use acknowledge that the software was developed 14*35209Sbostic * by the University of California, Berkeley. The name of the 15*35209Sbostic * University may not be used to endorse or promote products derived 16*35209Sbostic * from this software without specific prior written permission. 17*35209Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 18*35209Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 19*35209Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20*35209Sbostic */ 21*35209Sbostic 22*35209Sbostic #ifndef lint 23*35209Sbostic char copyright[] = 24*35209Sbostic "@(#) Copyright (c) 1988 Mark Nudleman.\n\ 25*35209Sbostic @(#) Copyright (c) 1988 Regents of the University of California.\n\ 26*35209Sbostic All rights reserved.\n"; 27*35209Sbostic #endif /* not lint */ 28*35209Sbostic 29*35209Sbostic #ifndef lint 30*35209Sbostic static char sccsid[] = "@(#)main.c 5.1 (Berkeley) 07/21/88"; 31*35209Sbostic #endif /* not lint */ 32*35209Sbostic 33*35209Sbostic /* 34*35209Sbostic * Entry point, initialization, miscellaneous routines. 35*35209Sbostic */ 36*35209Sbostic 37*35209Sbostic #include "less.h" 38*35209Sbostic #include "position.h" 39*35209Sbostic 40*35209Sbostic public int ispipe; 41*35209Sbostic public char * first_cmd; 42*35209Sbostic public char * every_first_cmd; 43*35209Sbostic public int new_file; 44*35209Sbostic public int is_tty; 45*35209Sbostic public char *current_file; 46*35209Sbostic public char *previous_file; 47*35209Sbostic public POSITION prev_pos; 48*35209Sbostic public int any_display; 49*35209Sbostic public int scroll; 50*35209Sbostic public int ac; 51*35209Sbostic public char ** av; 52*35209Sbostic public int curr_ac; 53*35209Sbostic public int quitting; 54*35209Sbostic 55*35209Sbostic extern int file; 56*35209Sbostic extern int quit_at_eof; 57*35209Sbostic extern int cbufs; 58*35209Sbostic extern int errmsgs; 59*35209Sbostic 60*35209Sbostic #if LOGFILE 61*35209Sbostic public int logfile = -1; 62*35209Sbostic public int force_logfile = 0; 63*35209Sbostic public char * namelogfile = NULL; 64*35209Sbostic #endif 65*35209Sbostic 66*35209Sbostic #if EDITOR 67*35209Sbostic public char * editor; 68*35209Sbostic #endif 69*35209Sbostic 70*35209Sbostic #if TAGS 71*35209Sbostic extern char * tagfile; 72*35209Sbostic extern char * tagpattern; 73*35209Sbostic extern int tagoption; 74*35209Sbostic #endif 75*35209Sbostic 76*35209Sbostic 77*35209Sbostic /* 78*35209Sbostic * Edit a new file. 79*35209Sbostic * Filename "-" means standard input. 80*35209Sbostic * No filename means the "current" file, from the command line. 81*35209Sbostic */ 82*35209Sbostic public void 83*35209Sbostic edit(filename) 84*35209Sbostic register char *filename; 85*35209Sbostic { 86*35209Sbostic register int f; 87*35209Sbostic register char *m; 88*35209Sbostic POSITION initial_pos; 89*35209Sbostic char message[100]; 90*35209Sbostic static int didpipe; 91*35209Sbostic 92*35209Sbostic initial_pos = NULL_POSITION; 93*35209Sbostic if (filename == NULL || *filename == '\0') 94*35209Sbostic { 95*35209Sbostic if (curr_ac >= ac) 96*35209Sbostic { 97*35209Sbostic error("No current file"); 98*35209Sbostic return; 99*35209Sbostic } 100*35209Sbostic filename = save(av[curr_ac]); 101*35209Sbostic } else if (strcmp(filename, "#") == 0) 102*35209Sbostic { 103*35209Sbostic if (*previous_file == '\0') 104*35209Sbostic { 105*35209Sbostic error("no previous file"); 106*35209Sbostic return; 107*35209Sbostic } 108*35209Sbostic filename = save(previous_file); 109*35209Sbostic initial_pos = prev_pos; 110*35209Sbostic } else 111*35209Sbostic filename = save(filename); 112*35209Sbostic 113*35209Sbostic if (strcmp(filename, "-") == 0) 114*35209Sbostic { 115*35209Sbostic /* 116*35209Sbostic * Use standard input. 117*35209Sbostic */ 118*35209Sbostic if (didpipe) 119*35209Sbostic { 120*35209Sbostic error("Can view standard input only once"); 121*35209Sbostic return; 122*35209Sbostic } 123*35209Sbostic f = 0; 124*35209Sbostic } else if ((m = bad_file(filename, message, sizeof(message))) != NULL) 125*35209Sbostic { 126*35209Sbostic error(m); 127*35209Sbostic free(filename); 128*35209Sbostic return; 129*35209Sbostic } else if ((f = open(filename, 0)) < 0) 130*35209Sbostic { 131*35209Sbostic error(errno_message(filename, message, sizeof(message))); 132*35209Sbostic free(filename); 133*35209Sbostic return; 134*35209Sbostic } 135*35209Sbostic 136*35209Sbostic if (isatty(f)) 137*35209Sbostic { 138*35209Sbostic /* 139*35209Sbostic * Not really necessary to call this an error, 140*35209Sbostic * but if the control terminal (for commands) 141*35209Sbostic * and the input file (for data) are the same, 142*35209Sbostic * we get weird results at best. 143*35209Sbostic */ 144*35209Sbostic error("Can't take input from a terminal"); 145*35209Sbostic if (f > 0) 146*35209Sbostic close(f); 147*35209Sbostic free(filename); 148*35209Sbostic return; 149*35209Sbostic } 150*35209Sbostic 151*35209Sbostic #if LOGFILE 152*35209Sbostic if (f == 0 && namelogfile != NULL && is_tty) 153*35209Sbostic use_logfile(); 154*35209Sbostic #endif 155*35209Sbostic 156*35209Sbostic /* 157*35209Sbostic * We are now committed to using the new file. 158*35209Sbostic * Close the current input file and set up to use the new one. 159*35209Sbostic */ 160*35209Sbostic if (file > 0) 161*35209Sbostic close(file); 162*35209Sbostic new_file = 1; 163*35209Sbostic if (previous_file != NULL) 164*35209Sbostic free(previous_file); 165*35209Sbostic previous_file = current_file; 166*35209Sbostic current_file = filename; 167*35209Sbostic prev_pos = position(TOP); 168*35209Sbostic ispipe = (f == 0); 169*35209Sbostic if (ispipe) 170*35209Sbostic didpipe = 1; 171*35209Sbostic file = f; 172*35209Sbostic ch_init(cbufs, 0); 173*35209Sbostic init_mark(); 174*35209Sbostic 175*35209Sbostic if (every_first_cmd != NULL) 176*35209Sbostic first_cmd = every_first_cmd; 177*35209Sbostic 178*35209Sbostic if (is_tty) 179*35209Sbostic { 180*35209Sbostic int no_display = !any_display; 181*35209Sbostic any_display = 1; 182*35209Sbostic if (no_display && errmsgs > 0) 183*35209Sbostic { 184*35209Sbostic /* 185*35209Sbostic * We displayed some messages on error output 186*35209Sbostic * (file descriptor 2; see error() function). 187*35209Sbostic * Before erasing the screen contents, 188*35209Sbostic * display the file name and wait for a keystroke. 189*35209Sbostic */ 190*35209Sbostic error(filename); 191*35209Sbostic } 192*35209Sbostic /* 193*35209Sbostic * Indicate there is nothing displayed yet. 194*35209Sbostic */ 195*35209Sbostic pos_clear(); 196*35209Sbostic if (initial_pos != NULL_POSITION) 197*35209Sbostic jump_loc(initial_pos); 198*35209Sbostic clr_linenum(); 199*35209Sbostic } 200*35209Sbostic } 201*35209Sbostic 202*35209Sbostic /* 203*35209Sbostic * Edit the next file in the command line list. 204*35209Sbostic */ 205*35209Sbostic public void 206*35209Sbostic next_file(n) 207*35209Sbostic int n; 208*35209Sbostic { 209*35209Sbostic if (curr_ac + n >= ac) 210*35209Sbostic { 211*35209Sbostic if (quit_at_eof) 212*35209Sbostic quit(); 213*35209Sbostic error("No (N-th) next file"); 214*35209Sbostic } else 215*35209Sbostic edit(av[curr_ac += n]); 216*35209Sbostic } 217*35209Sbostic 218*35209Sbostic /* 219*35209Sbostic * Edit the previous file in the command line list. 220*35209Sbostic */ 221*35209Sbostic public void 222*35209Sbostic prev_file(n) 223*35209Sbostic int n; 224*35209Sbostic { 225*35209Sbostic if (curr_ac - n < 0) 226*35209Sbostic error("No (N-th) previous file"); 227*35209Sbostic else 228*35209Sbostic edit(av[curr_ac -= n]); 229*35209Sbostic } 230*35209Sbostic 231*35209Sbostic /* 232*35209Sbostic * Copy a file directly to standard output. 233*35209Sbostic * Used if standard output is not a tty. 234*35209Sbostic */ 235*35209Sbostic static void 236*35209Sbostic cat_file() 237*35209Sbostic { 238*35209Sbostic register int c; 239*35209Sbostic 240*35209Sbostic while ((c = ch_forw_get()) != EOI) 241*35209Sbostic putchr(c); 242*35209Sbostic flush(); 243*35209Sbostic } 244*35209Sbostic 245*35209Sbostic #if LOGFILE 246*35209Sbostic 247*35209Sbostic use_logfile() 248*35209Sbostic { 249*35209Sbostic int exists; 250*35209Sbostic int answer; 251*35209Sbostic char message[100]; 252*35209Sbostic 253*35209Sbostic /* 254*35209Sbostic * If he asked for a log file and we have opened standard input, 255*35209Sbostic * create the log file. 256*35209Sbostic * We take care not to blindly overwrite an existing file. 257*35209Sbostic */ 258*35209Sbostic end_logfile(); 259*35209Sbostic 260*35209Sbostic /* 261*35209Sbostic * {{ We could use access() here. }} 262*35209Sbostic */ 263*35209Sbostic exists = open(namelogfile, 0); 264*35209Sbostic close(exists); 265*35209Sbostic exists = (exists >= 0); 266*35209Sbostic 267*35209Sbostic if (exists && !force_logfile) 268*35209Sbostic { 269*35209Sbostic static char w[] = "WARNING: log file exists: "; 270*35209Sbostic strcpy(message, w); 271*35209Sbostic strtcpy(message+sizeof(w)-1, namelogfile, 272*35209Sbostic sizeof(message)-sizeof(w)); 273*35209Sbostic error(message); 274*35209Sbostic answer = 'X'; /* Ask the user what to do */ 275*35209Sbostic } else 276*35209Sbostic answer = 'O'; /* Create the log file */ 277*35209Sbostic 278*35209Sbostic loop: 279*35209Sbostic switch (answer) 280*35209Sbostic { 281*35209Sbostic case 'O': case 'o': 282*35209Sbostic logfile = creat(namelogfile, 0644); 283*35209Sbostic break; 284*35209Sbostic case 'A': case 'a': 285*35209Sbostic logfile = open(namelogfile, 1); 286*35209Sbostic if (lseek(logfile, (offset_t)0, 2) < 0) 287*35209Sbostic { 288*35209Sbostic close(logfile); 289*35209Sbostic logfile = -1; 290*35209Sbostic } 291*35209Sbostic break; 292*35209Sbostic case 'D': case 'd': 293*35209Sbostic answer = 0; /* Don't print an error message */ 294*35209Sbostic break; 295*35209Sbostic case 'q': 296*35209Sbostic quit(); 297*35209Sbostic default: 298*35209Sbostic putstr("\n Overwrite, Append, or Don't log? "); 299*35209Sbostic answer = getchr(); 300*35209Sbostic putstr("\n"); 301*35209Sbostic flush(); 302*35209Sbostic goto loop; 303*35209Sbostic } 304*35209Sbostic 305*35209Sbostic if (logfile < 0 && answer != 0) 306*35209Sbostic { 307*35209Sbostic sprintf(message, "Cannot write to \"%s\"", 308*35209Sbostic namelogfile); 309*35209Sbostic error(message); 310*35209Sbostic } 311*35209Sbostic } 312*35209Sbostic 313*35209Sbostic /* 314*35209Sbostic * Entry point. 315*35209Sbostic */ 316*35209Sbostic main(argc, argv) 317*35209Sbostic int argc; 318*35209Sbostic char *argv[]; 319*35209Sbostic { 320*35209Sbostic char *getenv(); 321*35209Sbostic 322*35209Sbostic 323*35209Sbostic /* 324*35209Sbostic * Process command line arguments and LESS environment arguments. 325*35209Sbostic * Command line arguments override environment arguments. 326*35209Sbostic */ 327*35209Sbostic init_prompt(); 328*35209Sbostic init_option(); 329*35209Sbostic scan_option(getenv("LESS")); 330*35209Sbostic argv++; 331*35209Sbostic while ( (--argc > 0) && 332*35209Sbostic (argv[0][0] == '-' || argv[0][0] == '+') && 333*35209Sbostic argv[0][1] != '\0') 334*35209Sbostic scan_option(*argv++); 335*35209Sbostic 336*35209Sbostic #if EDITOR 337*35209Sbostic editor = getenv("EDITOR"); 338*35209Sbostic if (editor == NULL || *editor == '\0') 339*35209Sbostic editor = EDIT_PGM; 340*35209Sbostic #endif 341*35209Sbostic 342*35209Sbostic /* 343*35209Sbostic * Set up list of files to be examined. 344*35209Sbostic */ 345*35209Sbostic ac = argc; 346*35209Sbostic av = argv; 347*35209Sbostic curr_ac = 0; 348*35209Sbostic 349*35209Sbostic /* 350*35209Sbostic * Set up terminal, etc. 351*35209Sbostic */ 352*35209Sbostic is_tty = isatty(1); 353*35209Sbostic if (!is_tty) 354*35209Sbostic { 355*35209Sbostic /* 356*35209Sbostic * Output is not a tty. 357*35209Sbostic * Just copy the input file(s) to output. 358*35209Sbostic */ 359*35209Sbostic if (ac < 1) 360*35209Sbostic { 361*35209Sbostic edit("-"); 362*35209Sbostic cat_file(); 363*35209Sbostic } else 364*35209Sbostic { 365*35209Sbostic do 366*35209Sbostic { 367*35209Sbostic edit((char *)NULL); 368*35209Sbostic if (file >= 0) 369*35209Sbostic cat_file(); 370*35209Sbostic } while (++curr_ac < ac); 371*35209Sbostic } 372*35209Sbostic exit(0); 373*35209Sbostic } 374*35209Sbostic 375*35209Sbostic raw_mode(1); 376*35209Sbostic get_term(); 377*35209Sbostic open_getchr(); 378*35209Sbostic init(); 379*35209Sbostic init_cmd(); 380*35209Sbostic 381*35209Sbostic init_signals(1); 382*35209Sbostic 383*35209Sbostic /* 384*35209Sbostic * Select the first file to examine. 385*35209Sbostic */ 386*35209Sbostic #if TAGS 387*35209Sbostic if (tagoption) 388*35209Sbostic { 389*35209Sbostic /* 390*35209Sbostic * A -t option was given. 391*35209Sbostic * Verify that no filenames were also given. 392*35209Sbostic * Edit the file selected by the "tags" search, 393*35209Sbostic * and search for the proper line in the file. 394*35209Sbostic */ 395*35209Sbostic if (ac > 0) 396*35209Sbostic { 397*35209Sbostic error("No filenames allowed with -t option"); 398*35209Sbostic quit(); 399*35209Sbostic } 400*35209Sbostic if (tagfile == NULL) 401*35209Sbostic quit(); 402*35209Sbostic edit(tagfile); 403*35209Sbostic if (file < 0) 404*35209Sbostic quit(); 405*35209Sbostic if (tagsearch()) 406*35209Sbostic quit(); 407*35209Sbostic } else 408*35209Sbostic #endif 409*35209Sbostic if (ac < 1) 410*35209Sbostic edit("-"); /* Standard input */ 411*35209Sbostic else 412*35209Sbostic { 413*35209Sbostic /* 414*35209Sbostic * Try all the files named as command arguments. 415*35209Sbostic * We are simply looking for one which can be 416*35209Sbostic * opened without error. 417*35209Sbostic */ 418*35209Sbostic do 419*35209Sbostic { 420*35209Sbostic edit((char *)NULL); 421*35209Sbostic } while (file < 0 && ++curr_ac < ac); 422*35209Sbostic } 423*35209Sbostic 424*35209Sbostic if (file >= 0) 425*35209Sbostic commands(); 426*35209Sbostic quit(); 427*35209Sbostic /*NOTREACHED*/ 428*35209Sbostic } 429*35209Sbostic 430*35209Sbostic /* 431*35209Sbostic * Copy a string, truncating to the specified length if necessary. 432*35209Sbostic * Unlike strncpy(), the resulting string is guaranteed to be null-terminated. 433*35209Sbostic */ 434*35209Sbostic public void 435*35209Sbostic strtcpy(to, from, len) 436*35209Sbostic char *to; 437*35209Sbostic char *from; 438*35209Sbostic unsigned int len; 439*35209Sbostic { 440*35209Sbostic strncpy(to, from, len); 441*35209Sbostic to[len-1] = '\0'; 442*35209Sbostic } 443*35209Sbostic 444*35209Sbostic /* 445*35209Sbostic * Copy a string to a "safe" place 446*35209Sbostic * (that is, to a buffer allocated by calloc). 447*35209Sbostic */ 448*35209Sbostic public char * 449*35209Sbostic save(s) 450*35209Sbostic char *s; 451*35209Sbostic { 452*35209Sbostic register char *p; 453*35209Sbostic 454*35209Sbostic p = calloc(strlen(s)+1, sizeof(char)); 455*35209Sbostic if (p == NULL) 456*35209Sbostic { 457*35209Sbostic error("cannot allocate memory"); 458*35209Sbostic quit(); 459*35209Sbostic } 460*35209Sbostic strcpy(p, s); 461*35209Sbostic return (p); 462*35209Sbostic } 463*35209Sbostic 464*35209Sbostic /* 465*35209Sbostic * Exit the program. 466*35209Sbostic */ 467*35209Sbostic public void 468*35209Sbostic quit() 469*35209Sbostic { 470*35209Sbostic /* 471*35209Sbostic * Put cursor at bottom left corner, clear the line, 472*35209Sbostic * reset the terminal modes, and exit. 473*35209Sbostic */ 474*35209Sbostic quitting = 1; 475*35209Sbostic #if LOGFILE 476*35209Sbostic end_logfile(); 477*35209Sbostic #endif 478*35209Sbostic lower_left(); 479*35209Sbostic clear_eol(); 480*35209Sbostic deinit(); 481*35209Sbostic flush(); 482*35209Sbostic raw_mode(0); 483*35209Sbostic exit(0); 484*35209Sbostic } 485