main.c revision 128348
160812Sps/* $FreeBSD: head/contrib/less/main.c 128348 2004-04-17 07:24:09Z tjr $ */ 260786Sps/* 3128348Stjr * Copyright (C) 1984-2002 Mark Nudelman 460786Sps * 560786Sps * You may distribute under the terms of either the GNU General Public 660786Sps * License or the Less License, as specified in the README file. 760786Sps * 860786Sps * For more information about less, or for information on how to 960786Sps * contact the author, see the README file. 1060786Sps */ 1160786Sps 1260786Sps 1360786Sps/* 1460786Sps * Entry point, initialization, miscellaneous routines. 1560786Sps */ 1660786Sps 1760786Sps#include "less.h" 1889022Sps#if MSDOS_COMPILER==WIN32C 1989022Sps#include <windows.h> 2089022Sps#endif 2160786Sps 2260786Spspublic char * every_first_cmd = NULL; 2360786Spspublic int new_file; 2460786Spspublic int is_tty; 2560786Spspublic IFILE curr_ifile = NULL_IFILE; 2660786Spspublic IFILE old_ifile = NULL_IFILE; 2760786Spspublic struct scrpos initial_scrpos; 2860786Spspublic int any_display = FALSE; 2960786Spspublic POSITION start_attnpos = NULL_POSITION; 3060786Spspublic POSITION end_attnpos = NULL_POSITION; 3160786Spspublic int wscroll; 3260786Spspublic char * progname; 3360786Spspublic int quitting; 3460786Spspublic int secure; 3560786Spspublic int dohelp; 3660812Spspublic int more_mode = 0; 3760786Sps 3860786Sps#if LOGFILE 3960786Spspublic int logfile = -1; 4060786Spspublic int force_logfile = FALSE; 4160786Spspublic char * namelogfile = NULL; 4260786Sps#endif 4360786Sps 4460786Sps#if EDITOR 4560786Spspublic char * editor; 4660786Spspublic char * editproto; 4760786Sps#endif 4860786Sps 4960786Sps#if TAGS 5089022Spsextern char * tags; 5160786Spsextern char * tagoption; 5260786Spsextern int jump_sline; 5360786Sps#endif 5460786Sps 5589022Sps#ifdef WIN32 5689022Spsstatic char consoleTitle[256]; 5789022Sps#endif 5889022Sps 5960786Spsextern int missing_cap; 6060786Spsextern int know_dumb; 6160786Sps 6260786Sps 6360786Sps/* 6460786Sps * Entry point. 6560786Sps */ 6660786Spsint 6760786Spsmain(argc, argv) 6860786Sps int argc; 6960786Sps char *argv[]; 7060786Sps{ 7160786Sps IFILE ifile; 7260786Sps char *s; 7360812Sps extern char *__progname; 7460786Sps 7560786Sps#ifdef __EMX__ 7660786Sps _response(&argc, &argv); 7760786Sps _wildcard(&argc, &argv); 7860786Sps#endif 7960786Sps 8060786Sps progname = *argv++; 8160786Sps argc--; 8260786Sps 8360786Sps secure = 0; 8460786Sps s = lgetenv("LESSSECURE"); 8560786Sps if (s != NULL && *s != '\0') 8660786Sps secure = 1; 8760786Sps 8860786Sps#ifdef WIN32 8960786Sps if (getenv("HOME") == NULL) 9060786Sps { 9160786Sps /* 9260786Sps * If there is no HOME environment variable, 9360786Sps * try the concatenation of HOMEDRIVE + HOMEPATH. 9460786Sps */ 9560786Sps char *drive = getenv("HOMEDRIVE"); 9660786Sps char *path = getenv("HOMEPATH"); 9760786Sps if (drive != NULL && path != NULL) 9860786Sps { 9960786Sps char *env = (char *) ecalloc(strlen(drive) + 10060786Sps strlen(path) + 6, sizeof(char)); 10160786Sps strcpy(env, "HOME="); 10260786Sps strcat(env, drive); 10360786Sps strcat(env, path); 10460786Sps putenv(env); 10560786Sps } 10660786Sps } 10789022Sps GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char)); 10860786Sps#endif /* WIN32 */ 10960786Sps 11060786Sps /* 11160786Sps * Process command line arguments and LESS environment arguments. 11260786Sps * Command line arguments override environment arguments. 11360786Sps */ 11460812Sps if (strcmp(__progname, "more") == 0) 11560812Sps more_mode = 1; 11660812Sps 11760786Sps is_tty = isatty(1); 11860786Sps get_term(); 11960786Sps init_cmds(); 12060786Sps init_prompt(); 12160786Sps init_charset(); 12260786Sps init_line(); 12360786Sps init_option(); 12460812Sps 12560812Sps if (more_mode) { 12660812Sps scan_option("-E"); 12760812Sps scan_option("-m"); 12860812Sps scan_option("-G"); 12960812Sps scan_option("-f"); 13060812Sps s = lgetenv("MORE"); 13160812Sps } else { 13260812Sps s = lgetenv("LESS"); 13360812Sps } 13460786Sps if (s != NULL) 13560786Sps scan_option(save(s)); 13660786Sps 13760786Sps#define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 13860786Sps while (argc > 0 && (isoptstring(*argv) || isoptpending())) 13960786Sps { 14060786Sps s = *argv++; 14160786Sps argc--; 14260786Sps if (strcmp(s, "--") == 0) 14360786Sps break; 14460786Sps scan_option(s); 14560786Sps } 14660786Sps#undef isoptstring 14760786Sps 14860786Sps if (isoptpending()) 14960786Sps { 15060786Sps /* 15160786Sps * Last command line option was a flag requiring a 15260786Sps * following string, but there was no following string. 15360786Sps */ 15460786Sps nopendopt(); 15560786Sps quit(QUIT_OK); 15660786Sps } 15760786Sps 15860786Sps#if EDITOR 15960786Sps editor = lgetenv("VISUAL"); 16060786Sps if (editor == NULL || *editor == '\0') 16160786Sps { 16260786Sps editor = lgetenv("EDITOR"); 16360786Sps if (editor == NULL || *editor == '\0') 16460786Sps editor = EDIT_PGM; 16560786Sps } 16660786Sps editproto = lgetenv("LESSEDIT"); 16760786Sps if (editproto == NULL || *editproto == '\0') 16860786Sps editproto = "%E ?lm+%lm. %f"; 16960786Sps#endif 17060786Sps 17160786Sps /* 17260786Sps * Call get_ifile with all the command line filenames 17360786Sps * to "register" them with the ifile system. 17460786Sps */ 17560786Sps ifile = NULL_IFILE; 17660786Sps if (dohelp) 17760786Sps ifile = get_ifile(FAKE_HELPFILE, ifile); 17860786Sps while (argc-- > 0) 17960786Sps { 180128348Stjr char *filename; 18189022Sps#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 18260786Sps /* 18360786Sps * Because the "shell" doesn't expand filename patterns, 18460786Sps * treat each argument as a filename pattern rather than 18560786Sps * a single filename. 18660786Sps * Expand the pattern and iterate over the expanded list. 18760786Sps */ 18860786Sps struct textlist tlist; 18960786Sps char *gfilename; 19060786Sps 19160786Sps gfilename = lglob(*argv++); 19260786Sps init_textlist(&tlist, gfilename); 19360786Sps filename = NULL; 19460786Sps while ((filename = forw_textlist(&tlist, filename)) != NULL) 195128348Stjr { 196128348Stjr (void) get_ifile(filename, ifile); 197128348Stjr ifile = prev_ifile(NULL_IFILE); 198128348Stjr } 19960786Sps free(gfilename); 20060786Sps#else 201128348Stjr filename = shell_quote(*argv); 202128348Stjr if (filename == NULL) 203128348Stjr filename = *argv; 204128348Stjr argv++; 205128348Stjr (void) get_ifile(filename, ifile); 206128348Stjr ifile = prev_ifile(NULL_IFILE); 20760786Sps#endif 20860786Sps } 20960786Sps /* 21060786Sps * Set up terminal, etc. 21160786Sps */ 21260786Sps if (!is_tty) 21360786Sps { 21460786Sps /* 21560786Sps * Output is not a tty. 21660786Sps * Just copy the input file(s) to output. 21760786Sps */ 21860786Sps SET_BINARY(1); 21960786Sps if (nifile() == 0) 22060786Sps { 22160786Sps if (edit_stdin() == 0) 22260786Sps cat_file(); 22360786Sps } else if (edit_first() == 0) 22460786Sps { 22560786Sps do { 22660786Sps cat_file(); 22760786Sps } while (edit_next(1) == 0); 22860786Sps } 22960786Sps quit(QUIT_OK); 23060786Sps } 23160786Sps 23260812Sps if (missing_cap && !know_dumb && !more_mode) 23360786Sps error("WARNING: terminal is not fully functional", NULL_PARG); 23460786Sps init_mark(); 235128348Stjr open_getchr(); 23660786Sps raw_mode(1); 23760786Sps init_signals(1); 23860786Sps 23960786Sps /* 24060786Sps * Select the first file to examine. 24160786Sps */ 24260786Sps#if TAGS 24389022Sps if (tagoption != NULL || strcmp(tags, "-") == 0) 24460786Sps { 24560786Sps /* 24660786Sps * A -t option was given. 24760786Sps * Verify that no filenames were also given. 24860786Sps * Edit the file selected by the "tags" search, 24960786Sps * and search for the proper line in the file. 25060786Sps */ 25160786Sps if (nifile() > 0) 25260786Sps { 25360786Sps error("No filenames allowed with -t option", NULL_PARG); 25460786Sps quit(QUIT_ERROR); 25560786Sps } 25660786Sps findtag(tagoption); 25760786Sps if (edit_tagfile()) /* Edit file which contains the tag */ 25860786Sps quit(QUIT_ERROR); 25960786Sps /* 26060786Sps * Search for the line which contains the tag. 26160786Sps * Set up initial_scrpos so we display that line. 26260786Sps */ 26360786Sps initial_scrpos.pos = tagsearch(); 26460786Sps if (initial_scrpos.pos == NULL_POSITION) 26560786Sps quit(QUIT_ERROR); 26660786Sps initial_scrpos.ln = jump_sline; 26760786Sps } else 26860786Sps#endif 26960786Sps if (nifile() == 0) 27060786Sps { 27160786Sps if (edit_stdin()) /* Edit standard input */ 27260786Sps quit(QUIT_ERROR); 27360786Sps } else 27460786Sps { 27560786Sps if (edit_first()) /* Edit first valid file in cmd line */ 27660786Sps quit(QUIT_ERROR); 27760786Sps } 27860786Sps 27960786Sps init(); 28060786Sps commands(); 28160786Sps quit(QUIT_OK); 28260786Sps /*NOTREACHED*/ 283128348Stjr return (0); 28460786Sps} 28560786Sps 28660786Sps/* 28760786Sps * Copy a string to a "safe" place 28860786Sps * (that is, to a buffer allocated by calloc). 28960786Sps */ 29060786Sps public char * 29160786Spssave(s) 29260786Sps char *s; 29360786Sps{ 29460786Sps register char *p; 29560786Sps 29660786Sps p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 29760786Sps strcpy(p, s); 29860786Sps return (p); 29960786Sps} 30060786Sps 30160786Sps/* 30260786Sps * Allocate memory. 30360786Sps * Like calloc(), but never returns an error (NULL). 30460786Sps */ 30560786Sps public VOID_POINTER 30660786Spsecalloc(count, size) 30760786Sps int count; 30860786Sps unsigned int size; 30960786Sps{ 31060786Sps register VOID_POINTER p; 31160786Sps 31260786Sps p = (VOID_POINTER) calloc(count, size); 31360786Sps if (p != NULL) 31460786Sps return (p); 31560786Sps error("Cannot allocate memory", NULL_PARG); 31660786Sps quit(QUIT_ERROR); 31760786Sps /*NOTREACHED*/ 318128348Stjr return (NULL); 31960786Sps} 32060786Sps 32160786Sps/* 32260786Sps * Skip leading spaces in a string. 32360786Sps */ 32460786Sps public char * 32560786Spsskipsp(s) 32660786Sps register char *s; 32760786Sps{ 32860786Sps while (*s == ' ' || *s == '\t') 32960786Sps s++; 33060786Sps return (s); 33160786Sps} 33260786Sps 33360786Sps/* 33460786Sps * See how many characters of two strings are identical. 33560786Sps * If uppercase is true, the first string must begin with an uppercase 33660786Sps * character; the remainder of the first string may be either case. 33760786Sps */ 33860786Sps public int 33960786Spssprefix(ps, s, uppercase) 34060786Sps char *ps; 34160786Sps char *s; 34260786Sps int uppercase; 34360786Sps{ 34460786Sps register int c; 34560786Sps register int sc; 34660786Sps register int len = 0; 34760786Sps 34860786Sps for ( ; *s != '\0'; s++, ps++) 34960786Sps { 35060786Sps c = *ps; 35160786Sps if (uppercase) 35260786Sps { 35360786Sps if (len == 0 && SIMPLE_IS_LOWER(c)) 35460786Sps return (-1); 35560786Sps if (SIMPLE_IS_UPPER(c)) 35660786Sps c = SIMPLE_TO_LOWER(c); 35760786Sps } 35860786Sps sc = *s; 35960786Sps if (len > 0 && SIMPLE_IS_UPPER(sc)) 36060786Sps sc = SIMPLE_TO_LOWER(sc); 36160786Sps if (c != sc) 36260786Sps break; 36360786Sps len++; 36460786Sps } 36560786Sps return (len); 36660786Sps} 36760786Sps 36860786Sps/* 36960786Sps * Exit the program. 37060786Sps */ 37160786Sps public void 37260786Spsquit(status) 37360786Sps int status; 37460786Sps{ 37560786Sps static int save_status; 37660786Sps 37760786Sps /* 37860786Sps * Put cursor at bottom left corner, clear the line, 37960786Sps * reset the terminal modes, and exit. 38060786Sps */ 38160786Sps if (status < 0) 38260786Sps status = save_status; 38360786Sps else 38460786Sps save_status = status; 38560786Sps quitting = 1; 38660786Sps edit((char*)NULL); 38760786Sps if (any_display && is_tty) 38860786Sps clear_bot(); 38960786Sps deinit(); 39060786Sps flush(); 39160786Sps raw_mode(0); 39260786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 39360786Sps /* 39460786Sps * If we don't close 2, we get some garbage from 39560786Sps * 2's buffer when it flushes automatically. 39660786Sps * I cannot track this one down RB 39760786Sps * The same bug shows up if we use ^C^C to abort. 39860786Sps */ 39960786Sps close(2); 40060786Sps#endif 40189022Sps#if WIN32 40289022Sps SetConsoleTitle(consoleTitle); 40389022Sps#endif 40460786Sps close_getchr(); 40560786Sps exit(status); 40660786Sps} 407