1: /* 2: * Entry point, initialization, miscellaneous routines. 3: */ 4: 5: #include "less.h" 6: #include "position.h" 7: #include <setjmp.h> 8: 9: public int ispipe; 10: public jmp_buf main_loop; 11: public char * first_cmd; 12: public char * every_first_cmd; 13: public int new_file; 14: public int is_tty; 15: public char current_file[128]; 16: public int any_display; 17: public int ac; 18: public char ** av; 19: public int curr_ac; 20: #if LOGFILE 21: public int logfile = -1; 22: public char * namelogfile = NULL; 23: #endif 24: #if EDITOR 25: public char * editor; 26: #endif 27: 28: extern int file; 29: extern int nbufs; 30: extern int sigs; 31: extern int quit_at_eof; 32: extern int p_nbufs, f_nbufs; 33: extern int back_scroll; 34: extern int top_scroll; 35: extern int sc_height; 36: extern int errmsgs; 37: 38: 39: /* 40: * Edit a new file. 41: * Filename "-" means standard input. 42: * No filename means the "current" file, from the command line. 43: */ 44: public void 45: edit(filename) 46: char *filename; 47: { 48: register int f; 49: char message[100]; 50: static didpipe; 51: 52: if (filename == NULL || *filename == '\0') 53: { 54: if (curr_ac >= ac) 55: { 56: error("No current file"); 57: return; 58: } 59: filename = av[curr_ac]; 60: } 61: if (strcmp(filename, "-") == 0) 62: { 63: /* 64: * Use standard input. 65: */ 66: if (didpipe) 67: { 68: error("Can view standard input only once"); 69: return; 70: } 71: f = 0; 72: } else if ((f = open(filename, 0)) < 0) 73: { 74: static char co[] = "Cannot open "; 75: strcpy(message, co); 76: strtcpy(message+sizeof(co)-1, filename, 77: sizeof(message)-sizeof(co)); 78: error(message); 79: return; 80: } 81: 82: if (isatty(f)) 83: { 84: /* 85: * Not really necessary to call this an error, 86: * but if the control terminal (for commands) 87: * and the input file (for data) are the same, 88: * we get weird results at best. 89: */ 90: error("Can't take input from a terminal"); 91: if (f > 0) 92: close(f); 93: return; 94: } 95: 96: #if LOGFILE 97: /* 98: * If he asked for a log file and we have opened standard input, 99: * create the log file. 100: * We take care not to blindly overwrite an existing file. 101: */ 102: end_logfile(); 103: if (f == 0 && namelogfile != NULL && is_tty) 104: { 105: int exists; 106: int answer; 107: 108: /* 109: * {{ We could use access() here. }} 110: */ 111: exists = open(namelogfile, 0); 112: close(exists); 113: exists = (exists >= 0); 114: 115: if (exists) 116: { 117: static char w[] = "WARNING: log file exists: "; 118: strcpy(message, w); 119: strtcpy(message+sizeof(w)-1, namelogfile, 120: sizeof(message)-sizeof(w)); 121: error(message); 122: answer = 'X'; /* Ask the user what to do */ 123: } else 124: answer = 'O'; /* Create the log file */ 125: 126: loop: 127: switch (answer) 128: { 129: case 'O': case 'o': 130: logfile = creat(namelogfile, 0644); 131: break; 132: case 'A': case 'a': 133: logfile = open(namelogfile, 1); 134: if (lseek(logfile, (off_t)0, 2) < 0) 135: { 136: close(logfile); 137: logfile = -1; 138: } 139: break; 140: case 'D': case 'd': 141: answer = 0; /* Don't print an error message */ 142: break; 143: case 'q': 144: quit(); 145: default: 146: puts("\n Overwrite, Append, or Don't log? "); 147: answer = getc(); 148: puts("\n"); 149: flush(); 150: goto loop; 151: } 152: 153: if (logfile < 0 && answer != 0) 154: { 155: sprintf(message, "Cannot write to \"%s\"", 156: namelogfile); 157: error(message); 158: } 159: } 160: #endif 161: 162: /* 163: * We are now committed to using the new file. 164: * Close the current input file and set up to use the new one. 165: */ 166: if (file > 0) 167: close(file); 168: new_file = 1; 169: strtcpy(current_file, filename, sizeof(current_file)); 170: ispipe = (f == 0); 171: if (ispipe) 172: didpipe = 1; 173: file = f; 174: ch_init( (ispipe) ? p_nbufs : f_nbufs ); 175: init_mark(); 176: 177: if (every_first_cmd != NULL) 178: first_cmd = every_first_cmd; 179: 180: if (is_tty) 181: { 182: int no_display = !any_display; 183: any_display = 1; 184: if (no_display && errmsgs > 0) 185: { 186: /* 187: * We displayed some messages on error output 188: * (file descriptor 2; see error() function). 189: * Before erasing the screen contents, 190: * display the file name and wait for a keystroke. 191: */ 192: error(filename); 193: } 194: /* 195: * Indicate there is nothing displayed yet. 196: */ 197: pos_clear(); 198: } 199: } 200: 201: /* 202: * Edit the next file in the command line list. 203: */ 204: public void 205: next_file(n) 206: int n; 207: { 208: if (curr_ac + n >= ac) 209: { 210: if (quit_at_eof) 211: quit(); 212: error("No (N-th) next file"); 213: } else 214: edit(av[curr_ac += n]); 215: } 216: 217: /* 218: * Edit the previous file in the command line list. 219: */ 220: public void 221: prev_file(n) 222: int n; 223: { 224: if (curr_ac - n < 0) 225: error("No (N-th) previous file"); 226: else 227: edit(av[curr_ac -= n]); 228: } 229: 230: /* 231: * Copy a file directly to standard output. 232: * Used if standard output is not a tty. 233: */ 234: static void 235: cat_file() 236: { 237: register int c; 238: 239: while ((c = ch_forw_get()) != EOF) 240: putc(c); 241: flush(); 242: } 243: 244: /* 245: * Entry point. 246: */ 247: main(argc, argv) 248: int argc; 249: char *argv[]; 250: { 251: char *getenv(); 252: 253: 254: /* 255: * Process command line arguments and LESS environment arguments. 256: * Command line arguments override environment arguments. 257: */ 258: init_option(); 259: scan_option(getenv("LESS")); 260: argv++; 261: while ( (--argc > 0) && 262: (argv[0][0] == '-' || argv[0][0] == '+') && 263: argv[0][1] != '\0') 264: scan_option(*argv++); 265: 266: #if EDITOR 267: editor = getenv("EDITOR"); 268: if (editor == NULL || *editor == '\0') 269: editor = EDIT_PGM; 270: #endif 271: 272: /* 273: * Set up list of files to be examined. 274: */ 275: ac = argc; 276: av = argv; 277: curr_ac = 0; 278: 279: /* 280: * Set up terminal, etc. 281: */ 282: is_tty = isatty(1); 283: if (!is_tty) 284: { 285: /* 286: * Output is not a tty. 287: * Just copy the input file(s) to output. 288: */ 289: if (ac < 1) 290: { 291: edit("-"); 292: cat_file(); 293: } else 294: { 295: do 296: { 297: edit((char *)NULL); 298: if (file >= 0) 299: cat_file(); 300: } while (++curr_ac < ac); 301: } 302: exit(0); 303: } 304: 305: raw_mode(1); 306: get_term(); 307: open_getc(); 308: init(); 309: 310: if (setjmp(main_loop)) 311: quit(); 312: init_signals(); 313: 314: /* 315: * Select the first file to examine. 316: */ 317: if (ac < 1) 318: edit("-"); /* Standard input */ 319: else 320: { 321: /* 322: * Try all the files named as command arguments. 323: * We are simply looking for one which can be 324: * opened without error. 325: */ 326: do 327: { 328: edit((char *)NULL); 329: } while (file < 0 && ++curr_ac < ac); 330: } 331: 332: if (file >= 0) 333: commands(); 334: quit(); 335: } 336: 337: /* 338: * Copy a string, truncating to the specified length if necessary. 339: * Unlike strncpy(), the resulting string is guaranteed to be null-terminated. 340: */ 341: strtcpy(to, from, len) 342: char *to; 343: char *from; 344: int len; 345: { 346: strncpy(to, from, len); 347: to[len-1] = '\0'; 348: } 349: 350: /* 351: * Exit the program. 352: */ 353: public void 354: quit() 355: { 356: /* 357: * Put cursor at bottom left corner, clear the line, 358: * reset the terminal modes, and exit. 359: */ 360: #if LOGFILE 361: end_logfile(); 362: #endif 363: lower_left(); 364: clear_eol(); 365: deinit(); 366: flush(); 367: raw_mode(0); 368: exit(0); 369: }