main.c revision 89022
160812Sps/* $FreeBSD: head/contrib/less/main.c 89022 2002-01-07 20:37:09Z ps $ */ 260786Sps/* 360786Sps * Copyright (C) 1984-2000 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 { 18089022Sps#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 18160786Sps /* 18260786Sps * Because the "shell" doesn't expand filename patterns, 18360786Sps * treat each argument as a filename pattern rather than 18460786Sps * a single filename. 18560786Sps * Expand the pattern and iterate over the expanded list. 18660786Sps */ 18760786Sps struct textlist tlist; 18860786Sps char *gfilename; 18960786Sps char *filename; 19060786Sps 19160786Sps gfilename = lglob(*argv++); 19260786Sps init_textlist(&tlist, gfilename); 19360786Sps filename = NULL; 19460786Sps while ((filename = forw_textlist(&tlist, filename)) != NULL) 19560786Sps ifile = get_ifile(filename, ifile); 19660786Sps free(gfilename); 19760786Sps#else 19860786Sps ifile = get_ifile(*argv++, ifile); 19960786Sps#endif 20060786Sps } 20160786Sps /* 20260786Sps * Set up terminal, etc. 20360786Sps */ 20460786Sps if (!is_tty) 20560786Sps { 20660786Sps /* 20760786Sps * Output is not a tty. 20860786Sps * Just copy the input file(s) to output. 20960786Sps */ 21060786Sps SET_BINARY(1); 21160786Sps if (nifile() == 0) 21260786Sps { 21360786Sps if (edit_stdin() == 0) 21460786Sps cat_file(); 21560786Sps } else if (edit_first() == 0) 21660786Sps { 21760786Sps do { 21860786Sps cat_file(); 21960786Sps } while (edit_next(1) == 0); 22060786Sps } 22160786Sps quit(QUIT_OK); 22260786Sps } 22360786Sps 22460812Sps if (missing_cap && !know_dumb && !more_mode) 22560786Sps error("WARNING: terminal is not fully functional", NULL_PARG); 22660786Sps init_mark(); 22760786Sps raw_mode(1); 22860786Sps open_getchr(); 22960786Sps init_signals(1); 23060786Sps 23160786Sps 23260786Sps /* 23360786Sps * Select the first file to examine. 23460786Sps */ 23560786Sps#if TAGS 23689022Sps if (tagoption != NULL || strcmp(tags, "-") == 0) 23760786Sps { 23860786Sps /* 23960786Sps * A -t option was given. 24060786Sps * Verify that no filenames were also given. 24160786Sps * Edit the file selected by the "tags" search, 24260786Sps * and search for the proper line in the file. 24360786Sps */ 24460786Sps if (nifile() > 0) 24560786Sps { 24660786Sps error("No filenames allowed with -t option", NULL_PARG); 24760786Sps quit(QUIT_ERROR); 24860786Sps } 24960786Sps findtag(tagoption); 25060786Sps if (edit_tagfile()) /* Edit file which contains the tag */ 25160786Sps quit(QUIT_ERROR); 25260786Sps /* 25360786Sps * Search for the line which contains the tag. 25460786Sps * Set up initial_scrpos so we display that line. 25560786Sps */ 25660786Sps initial_scrpos.pos = tagsearch(); 25760786Sps if (initial_scrpos.pos == NULL_POSITION) 25860786Sps quit(QUIT_ERROR); 25960786Sps initial_scrpos.ln = jump_sline; 26060786Sps } else 26160786Sps#endif 26260786Sps if (nifile() == 0) 26360786Sps { 26460786Sps if (edit_stdin()) /* Edit standard input */ 26560786Sps quit(QUIT_ERROR); 26660786Sps } else 26760786Sps { 26860786Sps if (edit_first()) /* Edit first valid file in cmd line */ 26960786Sps quit(QUIT_ERROR); 27060786Sps } 27160786Sps 27260786Sps init(); 27360786Sps commands(); 27460786Sps quit(QUIT_OK); 27560786Sps /*NOTREACHED*/ 27660786Sps} 27760786Sps 27860786Sps/* 27960786Sps * Copy a string to a "safe" place 28060786Sps * (that is, to a buffer allocated by calloc). 28160786Sps */ 28260786Sps public char * 28360786Spssave(s) 28460786Sps char *s; 28560786Sps{ 28660786Sps register char *p; 28760786Sps 28860786Sps p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 28960786Sps strcpy(p, s); 29060786Sps return (p); 29160786Sps} 29260786Sps 29360786Sps/* 29460786Sps * Allocate memory. 29560786Sps * Like calloc(), but never returns an error (NULL). 29660786Sps */ 29760786Sps public VOID_POINTER 29860786Spsecalloc(count, size) 29960786Sps int count; 30060786Sps unsigned int size; 30160786Sps{ 30260786Sps register VOID_POINTER p; 30360786Sps 30460786Sps p = (VOID_POINTER) calloc(count, size); 30560786Sps if (p != NULL) 30660786Sps return (p); 30760786Sps error("Cannot allocate memory", NULL_PARG); 30860786Sps quit(QUIT_ERROR); 30960786Sps /*NOTREACHED*/ 31060786Sps} 31160786Sps 31260786Sps/* 31360786Sps * Skip leading spaces in a string. 31460786Sps */ 31560786Sps public char * 31660786Spsskipsp(s) 31760786Sps register char *s; 31860786Sps{ 31960786Sps while (*s == ' ' || *s == '\t') 32060786Sps s++; 32160786Sps return (s); 32260786Sps} 32360786Sps 32460786Sps/* 32560786Sps * See how many characters of two strings are identical. 32660786Sps * If uppercase is true, the first string must begin with an uppercase 32760786Sps * character; the remainder of the first string may be either case. 32860786Sps */ 32960786Sps public int 33060786Spssprefix(ps, s, uppercase) 33160786Sps char *ps; 33260786Sps char *s; 33360786Sps int uppercase; 33460786Sps{ 33560786Sps register int c; 33660786Sps register int sc; 33760786Sps register int len = 0; 33860786Sps 33960786Sps for ( ; *s != '\0'; s++, ps++) 34060786Sps { 34160786Sps c = *ps; 34260786Sps if (uppercase) 34360786Sps { 34460786Sps if (len == 0 && SIMPLE_IS_LOWER(c)) 34560786Sps return (-1); 34660786Sps if (SIMPLE_IS_UPPER(c)) 34760786Sps c = SIMPLE_TO_LOWER(c); 34860786Sps } 34960786Sps sc = *s; 35060786Sps if (len > 0 && SIMPLE_IS_UPPER(sc)) 35160786Sps sc = SIMPLE_TO_LOWER(sc); 35260786Sps if (c != sc) 35360786Sps break; 35460786Sps len++; 35560786Sps } 35660786Sps return (len); 35760786Sps} 35860786Sps 35960786Sps/* 36060786Sps * Exit the program. 36160786Sps */ 36260786Sps public void 36360786Spsquit(status) 36460786Sps int status; 36560786Sps{ 36660786Sps static int save_status; 36760786Sps 36860786Sps /* 36960786Sps * Put cursor at bottom left corner, clear the line, 37060786Sps * reset the terminal modes, and exit. 37160786Sps */ 37260786Sps if (status < 0) 37360786Sps status = save_status; 37460786Sps else 37560786Sps save_status = status; 37660786Sps quitting = 1; 37760786Sps edit((char*)NULL); 37860786Sps if (any_display && is_tty) 37960786Sps clear_bot(); 38060786Sps deinit(); 38160786Sps flush(); 38260786Sps raw_mode(0); 38360786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 38460786Sps /* 38560786Sps * If we don't close 2, we get some garbage from 38660786Sps * 2's buffer when it flushes automatically. 38760786Sps * I cannot track this one down RB 38860786Sps * The same bug shows up if we use ^C^C to abort. 38960786Sps */ 39060786Sps close(2); 39160786Sps#endif 39289022Sps#if WIN32 39389022Sps SetConsoleTitle(consoleTitle); 39489022Sps#endif 39560786Sps close_getchr(); 39660786Sps exit(status); 39760786Sps} 398