160812Sps/* $FreeBSD$ */ 260786Sps/* 3240121Sdelphij * Copyright (C) 1984-2012 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 * 8240121Sdelphij * For more information, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Entry point, initialization, miscellaneous routines. 1460786Sps */ 1560786Sps 1660786Sps#include "less.h" 1789022Sps#if MSDOS_COMPILER==WIN32C 1889022Sps#include <windows.h> 1989022Sps#endif 2060786Sps 2160786Spspublic char * every_first_cmd = NULL; 2260786Spspublic int new_file; 2360786Spspublic int is_tty; 2460786Spspublic IFILE curr_ifile = NULL_IFILE; 2560786Spspublic IFILE old_ifile = NULL_IFILE; 2660786Spspublic struct scrpos initial_scrpos; 2760786Spspublic int any_display = FALSE; 2860786Spspublic POSITION start_attnpos = NULL_POSITION; 2960786Spspublic POSITION end_attnpos = NULL_POSITION; 3060786Spspublic int wscroll; 3160786Spspublic char * progname; 3260786Spspublic int quitting; 3360786Spspublic int secure; 3460786Spspublic int dohelp; 3560786Sps 3660786Sps#if LOGFILE 3760786Spspublic int logfile = -1; 3860786Spspublic int force_logfile = FALSE; 3960786Spspublic char * namelogfile = NULL; 4060786Sps#endif 4160786Sps 4260786Sps#if EDITOR 4360786Spspublic char * editor; 4460786Spspublic char * editproto; 4560786Sps#endif 4660786Sps 4760786Sps#if TAGS 4889022Spsextern char * tags; 4960786Spsextern char * tagoption; 5060786Spsextern int jump_sline; 5160786Sps#endif 5260786Sps 5389022Sps#ifdef WIN32 5489022Spsstatic char consoleTitle[256]; 5589022Sps#endif 5689022Sps 57221715Sdelphijextern int less_is_more; 5860786Spsextern int missing_cap; 5960786Spsextern int know_dumb; 60170259Sdelphijextern int quit_if_one_screen; 61171009Sdelphijextern int no_init; 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(); 123195941Sdelphij init_search(); 124170259Sdelphij 125170259Sdelphij /* 126170259Sdelphij * If the name of the executable program is "more", 127170259Sdelphij * act like LESS_IS_MORE is set. 128170259Sdelphij */ 129170259Sdelphij for (s = progname + strlen(progname); s > progname; s--) 130170259Sdelphij { 131170259Sdelphij if (s[-1] == PATHNAME_SEP[0]) 132170259Sdelphij break; 13360812Sps } 134170259Sdelphij if (strcmp(s, "more") == 0) 135170259Sdelphij less_is_more = 1; 136170259Sdelphij 137170259Sdelphij init_prompt(); 138170259Sdelphij 139170812Sdelphij if (less_is_more) 140170812Sdelphij scan_option("-fG"); 141170812Sdelphij 142170259Sdelphij s = lgetenv(less_is_more ? "MORE" : "LESS"); 14360786Sps if (s != NULL) 14460786Sps scan_option(save(s)); 14560786Sps 146170963Sdelphij#define isoptstring(s) less_is_more ? (((s)[0] == '-') && (s)[1] != '\0') : \ 147170963Sdelphij (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 14860786Sps while (argc > 0 && (isoptstring(*argv) || isoptpending())) 14960786Sps { 15060786Sps s = *argv++; 15160786Sps argc--; 15260786Sps if (strcmp(s, "--") == 0) 15360786Sps break; 15460786Sps scan_option(s); 15560786Sps } 15660786Sps#undef isoptstring 15760786Sps 15860786Sps if (isoptpending()) 15960786Sps { 16060786Sps /* 16160786Sps * Last command line option was a flag requiring a 16260786Sps * following string, but there was no following string. 16360786Sps */ 16460786Sps nopendopt(); 16560786Sps quit(QUIT_OK); 16660786Sps } 16760786Sps 168171817Sdelphij if (less_is_more) 169171817Sdelphij no_init = TRUE; 170171817Sdelphij if (less_is_more && get_quit_at_eof()) 171171817Sdelphij quit_if_one_screen = TRUE; 172170259Sdelphij 17360786Sps#if EDITOR 17460786Sps editor = lgetenv("VISUAL"); 17560786Sps if (editor == NULL || *editor == '\0') 17660786Sps { 17760786Sps editor = lgetenv("EDITOR"); 17860786Sps if (editor == NULL || *editor == '\0') 17960786Sps editor = EDIT_PGM; 18060786Sps } 18160786Sps editproto = lgetenv("LESSEDIT"); 18260786Sps if (editproto == NULL || *editproto == '\0') 18360786Sps editproto = "%E ?lm+%lm. %f"; 18460786Sps#endif 18560786Sps 18660786Sps /* 18760786Sps * Call get_ifile with all the command line filenames 18860786Sps * to "register" them with the ifile system. 18960786Sps */ 19060786Sps ifile = NULL_IFILE; 19160786Sps if (dohelp) 19260786Sps ifile = get_ifile(FAKE_HELPFILE, ifile); 19360786Sps while (argc-- > 0) 19460786Sps { 195128348Stjr char *filename; 19689022Sps#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 19760786Sps /* 19860786Sps * Because the "shell" doesn't expand filename patterns, 19960786Sps * treat each argument as a filename pattern rather than 20060786Sps * a single filename. 20160786Sps * Expand the pattern and iterate over the expanded list. 20260786Sps */ 20360786Sps struct textlist tlist; 20460786Sps char *gfilename; 20560786Sps 20660786Sps gfilename = lglob(*argv++); 20760786Sps init_textlist(&tlist, gfilename); 20860786Sps filename = NULL; 20960786Sps while ((filename = forw_textlist(&tlist, filename)) != NULL) 210128348Stjr { 211128348Stjr (void) get_ifile(filename, ifile); 212128348Stjr ifile = prev_ifile(NULL_IFILE); 213128348Stjr } 21460786Sps free(gfilename); 21560786Sps#else 216128348Stjr filename = shell_quote(*argv); 217128348Stjr if (filename == NULL) 218128348Stjr filename = *argv; 219128348Stjr argv++; 220128348Stjr (void) get_ifile(filename, ifile); 221128348Stjr ifile = prev_ifile(NULL_IFILE); 222240121Sdelphij free(filename); 22360786Sps#endif 22460786Sps } 22560786Sps /* 22660786Sps * Set up terminal, etc. 22760786Sps */ 22860786Sps if (!is_tty) 22960786Sps { 23060786Sps /* 23160786Sps * Output is not a tty. 23260786Sps * Just copy the input file(s) to output. 23360786Sps */ 23460786Sps SET_BINARY(1); 23560786Sps if (nifile() == 0) 23660786Sps { 23760786Sps if (edit_stdin() == 0) 23860786Sps cat_file(); 23960786Sps } else if (edit_first() == 0) 24060786Sps { 24160786Sps do { 24260786Sps cat_file(); 24360786Sps } while (edit_next(1) == 0); 24460786Sps } 24560786Sps quit(QUIT_OK); 24660786Sps } 24760786Sps 248172045Sdelphij if (missing_cap && !know_dumb && !less_is_more) 24960786Sps error("WARNING: terminal is not fully functional", NULL_PARG); 25060786Sps init_mark(); 251128348Stjr open_getchr(); 25260786Sps raw_mode(1); 25360786Sps init_signals(1); 25460786Sps 25560786Sps /* 25660786Sps * Select the first file to examine. 25760786Sps */ 25860786Sps#if TAGS 25989022Sps if (tagoption != NULL || strcmp(tags, "-") == 0) 26060786Sps { 26160786Sps /* 26260786Sps * A -t option was given. 26360786Sps * Verify that no filenames were also given. 26460786Sps * Edit the file selected by the "tags" search, 26560786Sps * and search for the proper line in the file. 26660786Sps */ 26760786Sps if (nifile() > 0) 26860786Sps { 26960786Sps error("No filenames allowed with -t option", NULL_PARG); 27060786Sps quit(QUIT_ERROR); 27160786Sps } 27260786Sps findtag(tagoption); 27360786Sps if (edit_tagfile()) /* Edit file which contains the tag */ 27460786Sps quit(QUIT_ERROR); 27560786Sps /* 27660786Sps * Search for the line which contains the tag. 27760786Sps * Set up initial_scrpos so we display that line. 27860786Sps */ 27960786Sps initial_scrpos.pos = tagsearch(); 28060786Sps if (initial_scrpos.pos == NULL_POSITION) 28160786Sps quit(QUIT_ERROR); 28260786Sps initial_scrpos.ln = jump_sline; 28360786Sps } else 28460786Sps#endif 28560786Sps if (nifile() == 0) 28660786Sps { 28760786Sps if (edit_stdin()) /* Edit standard input */ 28860786Sps quit(QUIT_ERROR); 28960786Sps } else 29060786Sps { 29160786Sps if (edit_first()) /* Edit first valid file in cmd line */ 29260786Sps quit(QUIT_ERROR); 29360786Sps } 29460786Sps 29560786Sps init(); 29660786Sps commands(); 29760786Sps quit(QUIT_OK); 29860786Sps /*NOTREACHED*/ 299128348Stjr return (0); 30060786Sps} 30160786Sps 30260786Sps/* 30360786Sps * Copy a string to a "safe" place 30460786Sps * (that is, to a buffer allocated by calloc). 30560786Sps */ 30660786Sps public char * 30760786Spssave(s) 30860786Sps char *s; 30960786Sps{ 31060786Sps register char *p; 31160786Sps 31260786Sps p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 31360786Sps strcpy(p, s); 31460786Sps return (p); 31560786Sps} 31660786Sps 31760786Sps/* 31860786Sps * Allocate memory. 31960786Sps * Like calloc(), but never returns an error (NULL). 32060786Sps */ 32160786Sps public VOID_POINTER 32260786Spsecalloc(count, size) 32360786Sps int count; 32460786Sps unsigned int size; 32560786Sps{ 32660786Sps register VOID_POINTER p; 32760786Sps 32860786Sps p = (VOID_POINTER) calloc(count, size); 32960786Sps if (p != NULL) 33060786Sps return (p); 33160786Sps error("Cannot allocate memory", NULL_PARG); 33260786Sps quit(QUIT_ERROR); 33360786Sps /*NOTREACHED*/ 334128348Stjr return (NULL); 33560786Sps} 33660786Sps 33760786Sps/* 33860786Sps * Skip leading spaces in a string. 33960786Sps */ 34060786Sps public char * 34160786Spsskipsp(s) 34260786Sps register char *s; 34360786Sps{ 34460786Sps while (*s == ' ' || *s == '\t') 34560786Sps s++; 34660786Sps return (s); 34760786Sps} 34860786Sps 34960786Sps/* 35060786Sps * See how many characters of two strings are identical. 35160786Sps * If uppercase is true, the first string must begin with an uppercase 35260786Sps * character; the remainder of the first string may be either case. 35360786Sps */ 35460786Sps public int 35560786Spssprefix(ps, s, uppercase) 35660786Sps char *ps; 35760786Sps char *s; 35860786Sps int uppercase; 35960786Sps{ 36060786Sps register int c; 36160786Sps register int sc; 36260786Sps register int len = 0; 36360786Sps 36460786Sps for ( ; *s != '\0'; s++, ps++) 36560786Sps { 36660786Sps c = *ps; 36760786Sps if (uppercase) 36860786Sps { 369161478Sdelphij if (len == 0 && ASCII_IS_LOWER(c)) 37060786Sps return (-1); 371161478Sdelphij if (ASCII_IS_UPPER(c)) 372161478Sdelphij c = ASCII_TO_LOWER(c); 37360786Sps } 37460786Sps sc = *s; 375161478Sdelphij if (len > 0 && ASCII_IS_UPPER(sc)) 376161478Sdelphij sc = ASCII_TO_LOWER(sc); 37760786Sps if (c != sc) 37860786Sps break; 37960786Sps len++; 38060786Sps } 38160786Sps return (len); 38260786Sps} 38360786Sps 38460786Sps/* 38560786Sps * Exit the program. 38660786Sps */ 38760786Sps public void 38860786Spsquit(status) 38960786Sps int status; 39060786Sps{ 39160786Sps static int save_status; 39260786Sps 39360786Sps /* 39460786Sps * Put cursor at bottom left corner, clear the line, 39560786Sps * reset the terminal modes, and exit. 39660786Sps */ 39760786Sps if (status < 0) 39860786Sps status = save_status; 39960786Sps else 40060786Sps save_status = status; 40160786Sps quitting = 1; 40260786Sps edit((char*)NULL); 403161478Sdelphij save_cmdhist(); 40460786Sps if (any_display && is_tty) 40560786Sps clear_bot(); 40660786Sps deinit(); 40760786Sps flush(); 40860786Sps raw_mode(0); 40960786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 41060786Sps /* 41160786Sps * If we don't close 2, we get some garbage from 41260786Sps * 2's buffer when it flushes automatically. 41360786Sps * I cannot track this one down RB 41460786Sps * The same bug shows up if we use ^C^C to abort. 41560786Sps */ 41660786Sps close(2); 41760786Sps#endif 418221715Sdelphij#ifdef WIN32 41989022Sps SetConsoleTitle(consoleTitle); 42089022Sps#endif 42160786Sps close_getchr(); 42260786Sps exit(status); 42360786Sps} 424