main.c revision 170259
160812Sps/* $FreeBSD: head/contrib/less/main.c 170259 2007-06-04 01:43:11Z delphij $ */ 260786Sps/* 3170259Sdelphij * Copyright (C) 1984-2007 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; 36170259Sdelphijpublic int less_is_more; 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; 61170259Sdelphijextern int quit_if_one_screen; 62170259Sdelphijextern int pr_type; 6360786Sps 6460786Sps 6560786Sps/* 6660786Sps * Entry point. 6760786Sps */ 6860786Spsint 6960786Spsmain(argc, argv) 7060786Sps int argc; 7160786Sps char *argv[]; 7260786Sps{ 7360786Sps IFILE ifile; 7460786Sps char *s; 7560812Sps extern char *__progname; 7660786Sps 7760786Sps#ifdef __EMX__ 7860786Sps _response(&argc, &argv); 7960786Sps _wildcard(&argc, &argv); 8060786Sps#endif 8160786Sps 8260786Sps progname = *argv++; 8360786Sps argc--; 8460786Sps 8560786Sps secure = 0; 8660786Sps s = lgetenv("LESSSECURE"); 8760786Sps if (s != NULL && *s != '\0') 8860786Sps secure = 1; 8960786Sps 9060786Sps#ifdef WIN32 9160786Sps if (getenv("HOME") == NULL) 9260786Sps { 9360786Sps /* 9460786Sps * If there is no HOME environment variable, 9560786Sps * try the concatenation of HOMEDRIVE + HOMEPATH. 9660786Sps */ 9760786Sps char *drive = getenv("HOMEDRIVE"); 9860786Sps char *path = getenv("HOMEPATH"); 9960786Sps if (drive != NULL && path != NULL) 10060786Sps { 10160786Sps char *env = (char *) ecalloc(strlen(drive) + 10260786Sps strlen(path) + 6, sizeof(char)); 10360786Sps strcpy(env, "HOME="); 10460786Sps strcat(env, drive); 10560786Sps strcat(env, path); 10660786Sps putenv(env); 10760786Sps } 10860786Sps } 10989022Sps GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char)); 11060786Sps#endif /* WIN32 */ 11160786Sps 11260786Sps /* 11360786Sps * Process command line arguments and LESS environment arguments. 11460786Sps * Command line arguments override environment arguments. 11560786Sps */ 11660786Sps is_tty = isatty(1); 11760786Sps get_term(); 11860786Sps init_cmds(); 11960786Sps init_charset(); 12060786Sps init_line(); 121161478Sdelphij init_cmdhist(); 12260786Sps init_option(); 123170259Sdelphij 124170259Sdelphij /* 125170259Sdelphij * If the name of the executable program is "more", 126170259Sdelphij * act like LESS_IS_MORE is set. 127170259Sdelphij */ 128170259Sdelphij for (s = progname + strlen(progname); s > progname; s--) 129170259Sdelphij { 130170259Sdelphij if (s[-1] == PATHNAME_SEP[0]) 131170259Sdelphij break; 13260812Sps } 133170259Sdelphij if (strcmp(s, "more") == 0) 134170259Sdelphij less_is_more = 1; 135170259Sdelphij 136170259Sdelphij init_prompt(); 137170259Sdelphij 138170259Sdelphij s = lgetenv(less_is_more ? "MORE" : "LESS"); 13960786Sps if (s != NULL) 14060786Sps scan_option(save(s)); 14160786Sps 14260786Sps#define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 14360786Sps while (argc > 0 && (isoptstring(*argv) || isoptpending())) 14460786Sps { 14560786Sps s = *argv++; 14660786Sps argc--; 14760786Sps if (strcmp(s, "--") == 0) 14860786Sps break; 14960786Sps scan_option(s); 15060786Sps } 15160786Sps#undef isoptstring 15260786Sps 15360786Sps if (isoptpending()) 15460786Sps { 15560786Sps /* 15660786Sps * Last command line option was a flag requiring a 15760786Sps * following string, but there was no following string. 15860786Sps */ 15960786Sps nopendopt(); 16060786Sps quit(QUIT_OK); 16160786Sps } 16260786Sps 163170259Sdelphij if (less_is_more && get_quit_at_eof()) 164170259Sdelphij quit_if_one_screen = TRUE; 165170259Sdelphij 16660786Sps#if EDITOR 16760786Sps editor = lgetenv("VISUAL"); 16860786Sps if (editor == NULL || *editor == '\0') 16960786Sps { 17060786Sps editor = lgetenv("EDITOR"); 17160786Sps if (editor == NULL || *editor == '\0') 17260786Sps editor = EDIT_PGM; 17360786Sps } 17460786Sps editproto = lgetenv("LESSEDIT"); 17560786Sps if (editproto == NULL || *editproto == '\0') 17660786Sps editproto = "%E ?lm+%lm. %f"; 17760786Sps#endif 17860786Sps 17960786Sps /* 18060786Sps * Call get_ifile with all the command line filenames 18160786Sps * to "register" them with the ifile system. 18260786Sps */ 18360786Sps ifile = NULL_IFILE; 18460786Sps if (dohelp) 18560786Sps ifile = get_ifile(FAKE_HELPFILE, ifile); 18660786Sps while (argc-- > 0) 18760786Sps { 188128348Stjr char *filename; 18989022Sps#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 19060786Sps /* 19160786Sps * Because the "shell" doesn't expand filename patterns, 19260786Sps * treat each argument as a filename pattern rather than 19360786Sps * a single filename. 19460786Sps * Expand the pattern and iterate over the expanded list. 19560786Sps */ 19660786Sps struct textlist tlist; 19760786Sps char *gfilename; 19860786Sps 19960786Sps gfilename = lglob(*argv++); 20060786Sps init_textlist(&tlist, gfilename); 20160786Sps filename = NULL; 20260786Sps while ((filename = forw_textlist(&tlist, filename)) != NULL) 203128348Stjr { 204128348Stjr (void) get_ifile(filename, ifile); 205128348Stjr ifile = prev_ifile(NULL_IFILE); 206128348Stjr } 20760786Sps free(gfilename); 20860786Sps#else 209128348Stjr filename = shell_quote(*argv); 210128348Stjr if (filename == NULL) 211128348Stjr filename = *argv; 212128348Stjr argv++; 213128348Stjr (void) get_ifile(filename, ifile); 214128348Stjr ifile = prev_ifile(NULL_IFILE); 21560786Sps#endif 21660786Sps } 21760786Sps /* 21860786Sps * Set up terminal, etc. 21960786Sps */ 22060786Sps if (!is_tty) 22160786Sps { 22260786Sps /* 22360786Sps * Output is not a tty. 22460786Sps * Just copy the input file(s) to output. 22560786Sps */ 22660786Sps SET_BINARY(1); 22760786Sps if (nifile() == 0) 22860786Sps { 22960786Sps if (edit_stdin() == 0) 23060786Sps cat_file(); 23160786Sps } else if (edit_first() == 0) 23260786Sps { 23360786Sps do { 23460786Sps cat_file(); 23560786Sps } while (edit_next(1) == 0); 23660786Sps } 23760786Sps quit(QUIT_OK); 23860786Sps } 23960786Sps 240170259Sdelphij if (missing_cap && !know_dumb) 24160786Sps error("WARNING: terminal is not fully functional", NULL_PARG); 24260786Sps init_mark(); 243128348Stjr open_getchr(); 24460786Sps raw_mode(1); 24560786Sps init_signals(1); 24660786Sps 24760786Sps /* 24860786Sps * Select the first file to examine. 24960786Sps */ 25060786Sps#if TAGS 25189022Sps if (tagoption != NULL || strcmp(tags, "-") == 0) 25260786Sps { 25360786Sps /* 25460786Sps * A -t option was given. 25560786Sps * Verify that no filenames were also given. 25660786Sps * Edit the file selected by the "tags" search, 25760786Sps * and search for the proper line in the file. 25860786Sps */ 25960786Sps if (nifile() > 0) 26060786Sps { 26160786Sps error("No filenames allowed with -t option", NULL_PARG); 26260786Sps quit(QUIT_ERROR); 26360786Sps } 26460786Sps findtag(tagoption); 26560786Sps if (edit_tagfile()) /* Edit file which contains the tag */ 26660786Sps quit(QUIT_ERROR); 26760786Sps /* 26860786Sps * Search for the line which contains the tag. 26960786Sps * Set up initial_scrpos so we display that line. 27060786Sps */ 27160786Sps initial_scrpos.pos = tagsearch(); 27260786Sps if (initial_scrpos.pos == NULL_POSITION) 27360786Sps quit(QUIT_ERROR); 27460786Sps initial_scrpos.ln = jump_sline; 27560786Sps } else 27660786Sps#endif 27760786Sps if (nifile() == 0) 27860786Sps { 27960786Sps if (edit_stdin()) /* Edit standard input */ 28060786Sps quit(QUIT_ERROR); 28160786Sps } else 28260786Sps { 28360786Sps if (edit_first()) /* Edit first valid file in cmd line */ 28460786Sps quit(QUIT_ERROR); 28560786Sps } 28660786Sps 28760786Sps init(); 28860786Sps commands(); 28960786Sps quit(QUIT_OK); 29060786Sps /*NOTREACHED*/ 291128348Stjr return (0); 29260786Sps} 29360786Sps 29460786Sps/* 29560786Sps * Copy a string to a "safe" place 29660786Sps * (that is, to a buffer allocated by calloc). 29760786Sps */ 29860786Sps public char * 29960786Spssave(s) 30060786Sps char *s; 30160786Sps{ 30260786Sps register char *p; 30360786Sps 30460786Sps p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 30560786Sps strcpy(p, s); 30660786Sps return (p); 30760786Sps} 30860786Sps 30960786Sps/* 31060786Sps * Allocate memory. 31160786Sps * Like calloc(), but never returns an error (NULL). 31260786Sps */ 31360786Sps public VOID_POINTER 31460786Spsecalloc(count, size) 31560786Sps int count; 31660786Sps unsigned int size; 31760786Sps{ 31860786Sps register VOID_POINTER p; 31960786Sps 32060786Sps p = (VOID_POINTER) calloc(count, size); 32160786Sps if (p != NULL) 32260786Sps return (p); 32360786Sps error("Cannot allocate memory", NULL_PARG); 32460786Sps quit(QUIT_ERROR); 32560786Sps /*NOTREACHED*/ 326128348Stjr return (NULL); 32760786Sps} 32860786Sps 32960786Sps/* 33060786Sps * Skip leading spaces in a string. 33160786Sps */ 33260786Sps public char * 33360786Spsskipsp(s) 33460786Sps register char *s; 33560786Sps{ 33660786Sps while (*s == ' ' || *s == '\t') 33760786Sps s++; 33860786Sps return (s); 33960786Sps} 34060786Sps 34160786Sps/* 34260786Sps * See how many characters of two strings are identical. 34360786Sps * If uppercase is true, the first string must begin with an uppercase 34460786Sps * character; the remainder of the first string may be either case. 34560786Sps */ 34660786Sps public int 34760786Spssprefix(ps, s, uppercase) 34860786Sps char *ps; 34960786Sps char *s; 35060786Sps int uppercase; 35160786Sps{ 35260786Sps register int c; 35360786Sps register int sc; 35460786Sps register int len = 0; 35560786Sps 35660786Sps for ( ; *s != '\0'; s++, ps++) 35760786Sps { 35860786Sps c = *ps; 35960786Sps if (uppercase) 36060786Sps { 361161478Sdelphij if (len == 0 && ASCII_IS_LOWER(c)) 36260786Sps return (-1); 363161478Sdelphij if (ASCII_IS_UPPER(c)) 364161478Sdelphij c = ASCII_TO_LOWER(c); 36560786Sps } 36660786Sps sc = *s; 367161478Sdelphij if (len > 0 && ASCII_IS_UPPER(sc)) 368161478Sdelphij sc = ASCII_TO_LOWER(sc); 36960786Sps if (c != sc) 37060786Sps break; 37160786Sps len++; 37260786Sps } 37360786Sps return (len); 37460786Sps} 37560786Sps 37660786Sps/* 37760786Sps * Exit the program. 37860786Sps */ 37960786Sps public void 38060786Spsquit(status) 38160786Sps int status; 38260786Sps{ 38360786Sps static int save_status; 38460786Sps 38560786Sps /* 38660786Sps * Put cursor at bottom left corner, clear the line, 38760786Sps * reset the terminal modes, and exit. 38860786Sps */ 38960786Sps if (status < 0) 39060786Sps status = save_status; 39160786Sps else 39260786Sps save_status = status; 39360786Sps quitting = 1; 39460786Sps edit((char*)NULL); 395161478Sdelphij save_cmdhist(); 39660786Sps if (any_display && is_tty) 39760786Sps clear_bot(); 39860786Sps deinit(); 39960786Sps flush(); 40060786Sps raw_mode(0); 40160786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 40260786Sps /* 40360786Sps * If we don't close 2, we get some garbage from 40460786Sps * 2's buffer when it flushes automatically. 40560786Sps * I cannot track this one down RB 40660786Sps * The same bug shows up if we use ^C^C to abort. 40760786Sps */ 40860786Sps close(2); 40960786Sps#endif 41089022Sps#if WIN32 41189022Sps SetConsoleTitle(consoleTitle); 41289022Sps#endif 41360786Sps close_getchr(); 41460786Sps exit(status); 41560786Sps} 416