160812Sps/* $FreeBSD: stable/10/contrib/less/main.c 330571 2018-03-07 06:39:00Z delphij $ */ 2238730Sdelphij/* 3330571Sdelphij * Copyright (C) 1984-2017 Mark Nudelman 4238730Sdelphij * 5238730Sdelphij * You may distribute under the terms of either the GNU General Public 6238730Sdelphij * License or the Less License, as specified in the README file. 7238730Sdelphij * 8238730Sdelphij * For more information, see the README file. 9238730Sdelphij */ 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 57330571Sdelphijpublic int line_count; 58221715Sdelphijextern int less_is_more; 5960786Spsextern int missing_cap; 6060786Spsextern int know_dumb; 61171009Sdelphijextern int no_init; 62170259Sdelphijextern int pr_type; 63330571Sdelphijextern int quit_if_one_screen; 6460786Sps 6560786Sps 6660786Sps/* 6760786Sps * Entry point. 6860786Sps */ 6960786Spsint 7060786Spsmain(argc, argv) 7160786Sps int argc; 7260786Sps char *argv[]; 7360786Sps{ 7460786Sps IFILE ifile; 7560786Sps char *s; 7660812Sps extern char *__progname; 7760786Sps 7860786Sps#ifdef __EMX__ 7960786Sps _response(&argc, &argv); 8060786Sps _wildcard(&argc, &argv); 8160786Sps#endif 8260786Sps 8360786Sps progname = *argv++; 8460786Sps argc--; 8560786Sps 8660786Sps secure = 0; 8760786Sps s = lgetenv("LESSSECURE"); 8860786Sps if (s != NULL && *s != '\0') 8960786Sps secure = 1; 9060786Sps 9160786Sps#ifdef WIN32 9260786Sps if (getenv("HOME") == NULL) 9360786Sps { 9460786Sps /* 9560786Sps * If there is no HOME environment variable, 9660786Sps * try the concatenation of HOMEDRIVE + HOMEPATH. 9760786Sps */ 9860786Sps char *drive = getenv("HOMEDRIVE"); 9960786Sps char *path = getenv("HOMEPATH"); 10060786Sps if (drive != NULL && path != NULL) 10160786Sps { 10260786Sps char *env = (char *) ecalloc(strlen(drive) + 10360786Sps strlen(path) + 6, sizeof(char)); 10460786Sps strcpy(env, "HOME="); 10560786Sps strcat(env, drive); 10660786Sps strcat(env, path); 10760786Sps putenv(env); 10860786Sps } 10960786Sps } 11089022Sps GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char)); 11160786Sps#endif /* WIN32 */ 11260786Sps 11360786Sps /* 11460786Sps * Process command line arguments and LESS environment arguments. 11560786Sps * Command line arguments override environment arguments. 11660786Sps */ 11760786Sps is_tty = isatty(1); 118330571Sdelphij init_cmds(); 11960786Sps get_term(); 120330571Sdelphij expand_cmd_tables(); 12160786Sps init_charset(); 12260786Sps init_line(); 123161478Sdelphij init_cmdhist(); 12460786Sps init_option(); 125195941Sdelphij init_search(); 126170259Sdelphij 127170259Sdelphij /* 128170259Sdelphij * If the name of the executable program is "more", 129170259Sdelphij * act like LESS_IS_MORE is set. 130170259Sdelphij */ 131170259Sdelphij for (s = progname + strlen(progname); s > progname; s--) 132170259Sdelphij { 133170259Sdelphij if (s[-1] == PATHNAME_SEP[0]) 134170259Sdelphij break; 13560812Sps } 136170259Sdelphij if (strcmp(s, "more") == 0) 137170259Sdelphij less_is_more = 1; 138170259Sdelphij 139170259Sdelphij init_prompt(); 140170259Sdelphij 141170812Sdelphij if (less_is_more) 142170812Sdelphij scan_option("-fG"); 143170812Sdelphij 144170259Sdelphij s = lgetenv(less_is_more ? "MORE" : "LESS"); 14560786Sps if (s != NULL) 14660786Sps scan_option(save(s)); 14760786Sps 148170963Sdelphij#define isoptstring(s) less_is_more ? (((s)[0] == '-') && (s)[1] != '\0') : \ 149170963Sdelphij (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 15060786Sps while (argc > 0 && (isoptstring(*argv) || isoptpending())) 15160786Sps { 15260786Sps s = *argv++; 15360786Sps argc--; 15460786Sps if (strcmp(s, "--") == 0) 15560786Sps break; 15660786Sps scan_option(s); 15760786Sps } 15860786Sps#undef isoptstring 15960786Sps 16060786Sps if (isoptpending()) 16160786Sps { 16260786Sps /* 16360786Sps * Last command line option was a flag requiring a 16460786Sps * following string, but there was no following string. 16560786Sps */ 16660786Sps nopendopt(); 16760786Sps quit(QUIT_OK); 16860786Sps } 16960786Sps 170171817Sdelphij if (less_is_more) 171171817Sdelphij no_init = 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 { 19589022Sps#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 19660786Sps /* 19760786Sps * Because the "shell" doesn't expand filename patterns, 19860786Sps * treat each argument as a filename pattern rather than 19960786Sps * a single filename. 20060786Sps * Expand the pattern and iterate over the expanded list. 20160786Sps */ 20260786Sps struct textlist tlist; 203330571Sdelphij char *filename; 20460786Sps char *gfilename; 205330571Sdelphij char *qfilename; 20660786Sps 20760786Sps gfilename = lglob(*argv++); 20860786Sps init_textlist(&tlist, gfilename); 20960786Sps filename = NULL; 21060786Sps while ((filename = forw_textlist(&tlist, filename)) != NULL) 211128348Stjr { 212330571Sdelphij qfilename = shell_unquote(filename); 213330571Sdelphij (void) get_ifile(qfilename, ifile); 214330571Sdelphij free(qfilename); 215128348Stjr ifile = prev_ifile(NULL_IFILE); 216128348Stjr } 21760786Sps free(gfilename); 21860786Sps#else 219330571Sdelphij (void) get_ifile(*argv++, ifile); 220128348Stjr ifile = prev_ifile(NULL_IFILE); 22160786Sps#endif 22260786Sps } 22360786Sps /* 22460786Sps * Set up terminal, etc. 22560786Sps */ 22660786Sps if (!is_tty) 22760786Sps { 22860786Sps /* 22960786Sps * Output is not a tty. 23060786Sps * Just copy the input file(s) to output. 23160786Sps */ 23260786Sps SET_BINARY(1); 23360786Sps if (nifile() == 0) 23460786Sps { 23560786Sps if (edit_stdin() == 0) 23660786Sps cat_file(); 23760786Sps } else if (edit_first() == 0) 23860786Sps { 23960786Sps do { 24060786Sps cat_file(); 24160786Sps } while (edit_next(1) == 0); 24260786Sps } 24360786Sps quit(QUIT_OK); 24460786Sps } 24560786Sps 246172045Sdelphij if (missing_cap && !know_dumb && !less_is_more) 24760786Sps error("WARNING: terminal is not fully functional", NULL_PARG); 24860786Sps init_mark(); 249128348Stjr open_getchr(); 25060786Sps raw_mode(1); 25160786Sps init_signals(1); 25260786Sps 25360786Sps /* 25460786Sps * Select the first file to examine. 25560786Sps */ 25660786Sps#if TAGS 25789022Sps if (tagoption != NULL || strcmp(tags, "-") == 0) 25860786Sps { 25960786Sps /* 26060786Sps * A -t option was given. 26160786Sps * Verify that no filenames were also given. 26260786Sps * Edit the file selected by the "tags" search, 26360786Sps * and search for the proper line in the file. 26460786Sps */ 26560786Sps if (nifile() > 0) 26660786Sps { 26760786Sps error("No filenames allowed with -t option", NULL_PARG); 26860786Sps quit(QUIT_ERROR); 26960786Sps } 27060786Sps findtag(tagoption); 27160786Sps if (edit_tagfile()) /* Edit file which contains the tag */ 27260786Sps quit(QUIT_ERROR); 27360786Sps /* 27460786Sps * Search for the line which contains the tag. 27560786Sps * Set up initial_scrpos so we display that line. 27660786Sps */ 27760786Sps initial_scrpos.pos = tagsearch(); 27860786Sps if (initial_scrpos.pos == NULL_POSITION) 27960786Sps quit(QUIT_ERROR); 28060786Sps initial_scrpos.ln = jump_sline; 28160786Sps } else 28260786Sps#endif 28360786Sps if (nifile() == 0) 28460786Sps { 28560786Sps if (edit_stdin()) /* Edit standard input */ 28660786Sps quit(QUIT_ERROR); 287330571Sdelphij if (quit_if_one_screen) 288330571Sdelphij line_count = get_line_count(); 28960786Sps } else 29060786Sps { 29160786Sps if (edit_first()) /* Edit first valid file in cmd line */ 29260786Sps quit(QUIT_ERROR); 293330571Sdelphij if (quit_if_one_screen) 294330571Sdelphij { 295330571Sdelphij if (nifile() == 1) 296330571Sdelphij line_count = get_line_count(); 297330571Sdelphij else /* If more than one file, -F can not be used */ 298330571Sdelphij quit_if_one_screen = FALSE; 299330571Sdelphij } 30060786Sps } 30160786Sps 30260786Sps init(); 30360786Sps commands(); 30460786Sps quit(QUIT_OK); 30560786Sps /*NOTREACHED*/ 306128348Stjr return (0); 30760786Sps} 30860786Sps 30960786Sps/* 31060786Sps * Copy a string to a "safe" place 31160786Sps * (that is, to a buffer allocated by calloc). 31260786Sps */ 31360786Sps public char * 31460786Spssave(s) 315330571Sdelphij constant char *s; 31660786Sps{ 317330571Sdelphij char *p; 31860786Sps 31960786Sps p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 32060786Sps strcpy(p, s); 32160786Sps return (p); 32260786Sps} 32360786Sps 32460786Sps/* 32560786Sps * Allocate memory. 32660786Sps * Like calloc(), but never returns an error (NULL). 32760786Sps */ 32860786Sps public VOID_POINTER 32960786Spsecalloc(count, size) 33060786Sps int count; 33160786Sps unsigned int size; 33260786Sps{ 333330571Sdelphij VOID_POINTER p; 33460786Sps 33560786Sps p = (VOID_POINTER) calloc(count, size); 33660786Sps if (p != NULL) 33760786Sps return (p); 33860786Sps error("Cannot allocate memory", NULL_PARG); 33960786Sps quit(QUIT_ERROR); 34060786Sps /*NOTREACHED*/ 341128348Stjr return (NULL); 34260786Sps} 34360786Sps 34460786Sps/* 34560786Sps * Skip leading spaces in a string. 34660786Sps */ 34760786Sps public char * 34860786Spsskipsp(s) 349330571Sdelphij char *s; 35060786Sps{ 35160786Sps while (*s == ' ' || *s == '\t') 35260786Sps s++; 35360786Sps return (s); 35460786Sps} 35560786Sps 35660786Sps/* 35760786Sps * See how many characters of two strings are identical. 35860786Sps * If uppercase is true, the first string must begin with an uppercase 35960786Sps * character; the remainder of the first string may be either case. 36060786Sps */ 36160786Sps public int 36260786Spssprefix(ps, s, uppercase) 36360786Sps char *ps; 36460786Sps char *s; 36560786Sps int uppercase; 36660786Sps{ 367330571Sdelphij int c; 368330571Sdelphij int sc; 369330571Sdelphij int len = 0; 37060786Sps 37160786Sps for ( ; *s != '\0'; s++, ps++) 37260786Sps { 37360786Sps c = *ps; 37460786Sps if (uppercase) 37560786Sps { 376161478Sdelphij if (len == 0 && ASCII_IS_LOWER(c)) 37760786Sps return (-1); 378161478Sdelphij if (ASCII_IS_UPPER(c)) 379161478Sdelphij c = ASCII_TO_LOWER(c); 38060786Sps } 38160786Sps sc = *s; 382161478Sdelphij if (len > 0 && ASCII_IS_UPPER(sc)) 383161478Sdelphij sc = ASCII_TO_LOWER(sc); 38460786Sps if (c != sc) 38560786Sps break; 38660786Sps len++; 38760786Sps } 38860786Sps return (len); 38960786Sps} 39060786Sps 39160786Sps/* 39260786Sps * Exit the program. 39360786Sps */ 39460786Sps public void 39560786Spsquit(status) 39660786Sps int status; 39760786Sps{ 39860786Sps static int save_status; 39960786Sps 40060786Sps /* 40160786Sps * Put cursor at bottom left corner, clear the line, 40260786Sps * reset the terminal modes, and exit. 40360786Sps */ 40460786Sps if (status < 0) 40560786Sps status = save_status; 40660786Sps else 40760786Sps save_status = status; 40860786Sps quitting = 1; 40960786Sps edit((char*)NULL); 410161478Sdelphij save_cmdhist(); 41160786Sps if (any_display && is_tty) 41260786Sps clear_bot(); 41360786Sps deinit(); 41460786Sps flush(); 41560786Sps raw_mode(0); 41660786Sps#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 41760786Sps /* 41860786Sps * If we don't close 2, we get some garbage from 41960786Sps * 2's buffer when it flushes automatically. 42060786Sps * I cannot track this one down RB 42160786Sps * The same bug shows up if we use ^C^C to abort. 42260786Sps */ 42360786Sps close(2); 42460786Sps#endif 425221715Sdelphij#ifdef WIN32 42689022Sps SetConsoleTitle(consoleTitle); 42789022Sps#endif 42860786Sps close_getchr(); 42960786Sps exit(status); 43060786Sps} 431