main.c revision 128348
11541Srgrimes/* $FreeBSD: head/contrib/less/main.c 128348 2004-04-17 07:24:09Z tjr $ */ 21541Srgrimes/* 31541Srgrimes * Copyright (C) 1984-2002 Mark Nudelman 41541Srgrimes * 51541Srgrimes * You may distribute under the terms of either the GNU General Public 61541Srgrimes * License or the Less License, as specified in the README file. 71541Srgrimes * 81541Srgrimes * For more information about less, or for information on how to 91541Srgrimes * contact the author, see the README file. 101541Srgrimes */ 111541Srgrimes 121541Srgrimes 131541Srgrimes/* 141541Srgrimes * Entry point, initialization, miscellaneous routines. 151541Srgrimes */ 161541Srgrimes 171541Srgrimes#include "less.h" 181541Srgrimes#if MSDOS_COMPILER==WIN32C 191541Srgrimes#include <windows.h> 201541Srgrimes#endif 211541Srgrimes 221541Srgrimespublic char * every_first_cmd = NULL; 231541Srgrimespublic int new_file; 241541Srgrimespublic int is_tty; 251541Srgrimespublic IFILE curr_ifile = NULL_IFILE; 261541Srgrimespublic IFILE old_ifile = NULL_IFILE; 271541Srgrimespublic struct scrpos initial_scrpos; 281541Srgrimespublic int any_display = FALSE; 291541Srgrimespublic POSITION start_attnpos = NULL_POSITION; 301541Srgrimespublic POSITION end_attnpos = NULL_POSITION; 311541Srgrimespublic int wscroll; 321541Srgrimespublic char * progname; 331541Srgrimespublic int quitting; 3419622Sfennerpublic int secure; 3518797Swollmanpublic int dohelp; 361541Srgrimespublic int more_mode = 0; 371541Srgrimes 3818797Swollman#if LOGFILE 3918797Swollmanpublic int logfile = -1; 4016333Sgpalmerpublic int force_logfile = FALSE; 4116333Sgpalmerpublic char * namelogfile = NULL; 4219622Sfenner#endif 4319622Sfenner 441541Srgrimes#if EDITOR 451541Srgrimespublic char * editor; 461541Srgrimespublic char * editproto; 471541Srgrimes#endif 481541Srgrimes 491541Srgrimes#if TAGS 501541Srgrimesextern char * tags; 511541Srgrimesextern char * tagoption; 521541Srgrimesextern int jump_sline; 531541Srgrimes#endif 547091Swollman 557090Sbde#ifdef WIN32 561541Srgrimesstatic char consoleTitle[256]; 571541Srgrimes#endif 5819622Sfenner 591541Srgrimesextern int missing_cap; 608426Swollmanextern int know_dumb; 611541Srgrimes 621541Srgrimes 631541Srgrimes/* 647090Sbde * Entry point. 651541Srgrimes */ 661541Srgrimesint 671541Srgrimesmain(argc, argv) 681541Srgrimes int argc; 691541Srgrimes char *argv[]; 7018797Swollman{ 711541Srgrimes IFILE ifile; 722531Swollman char *s; 7315680Sgpalmer extern char *__progname; 7415680Sgpalmer 7515680Sgpalmer#ifdef __EMX__ 7615680Sgpalmer _response(&argc, &argv); 7715680Sgpalmer _wildcard(&argc, &argv); 789209Swollman#endif 7912820Sphk 802531Swollman progname = *argv++; 812531Swollman argc--; 8213266Swollman 8312296Sphk secure = 0; 8412296Sphk s = lgetenv("LESSSECURE"); 8512296Sphk if (s != NULL && *s != '\0') 8613266Swollman secure = 1; 8712296Sphk 8812296Sphk#ifdef WIN32 8912296Sphk if (getenv("HOME") == NULL) 901541Srgrimes { 9112296Sphk /* 9212296Sphk * If there is no HOME environment variable, 9312296Sphk * try the concatenation of HOMEDRIVE + HOMEPATH. 9412296Sphk */ 9512296Sphk char *drive = getenv("HOMEDRIVE"); 9612296Sphk char *path = getenv("HOMEPATH"); 971541Srgrimes if (drive != NULL && path != NULL) 9812296Sphk { 991541Srgrimes char *env = (char *) ecalloc(strlen(drive) + 1001541Srgrimes strlen(path) + 6, sizeof(char)); 1011541Srgrimes strcpy(env, "HOME="); 1021541Srgrimes strcat(env, drive); 1031541Srgrimes strcat(env, path); 10412296Sphk putenv(env); 1051541Srgrimes } 1061541Srgrimes } 10712296Sphk GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char)); 10812296Sphk#endif /* WIN32 */ 10912296Sphk 11012296Sphk /* 1111541Srgrimes * Process command line arguments and LESS environment arguments. 1122112Swollman * Command line arguments override environment arguments. 11312820Sphk */ 1142112Swollman if (strcmp(__progname, "more") == 0) 11512296Sphk more_mode = 1; 11612296Sphk 11712296Sphk is_tty = isatty(1); 11812296Sphk get_term(); 11912296Sphk init_cmds(); 12018797Swollman init_prompt(); 12118797Swollman init_charset(); 12218797Swollman init_line(); 12318797Swollman init_option(); 12418797Swollman 12518797Swollman if (more_mode) { 12618797Swollman scan_option("-E"); 12718797Swollman scan_option("-m"); 12815026Sphk scan_option("-G"); 12915026Sphk scan_option("-f"); 13015026Sphk s = lgetenv("MORE"); 13114209Sphk } else { 13217758Ssos s = lgetenv("LESS"); 13317758Ssos } 13417758Ssos if (s != NULL) 13518797Swollman scan_option(save(s)); 13617758Ssos 13714209Sphk#define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 1381541Srgrimes while (argc > 0 && (isoptstring(*argv) || isoptpending())) 1391541Srgrimes { 1401541Srgrimes s = *argv++; 1411541Srgrimes argc--; 1421541Srgrimes if (strcmp(s, "--") == 0) 1431541Srgrimes break; 14412296Sphk scan_option(s); 1451541Srgrimes } 1461541Srgrimes#undef isoptstring 1471541Srgrimes 1481541Srgrimes if (isoptpending()) 1491541Srgrimes { 1501541Srgrimes /* 1511541Srgrimes * Last command line option was a flag requiring a 15217072Sjulian * following string, but there was no following string. 15317072Sjulian */ 15417072Sjulian nopendopt(); 15517072Sjulian quit(QUIT_OK); 15617072Sjulian } 15717072Sjulian 15817072Sjulian#if EDITOR 15917072Sjulian editor = lgetenv("VISUAL"); 16017072Sjulian if (editor == NULL || *editor == '\0') 1611541Srgrimes { 16212296Sphk editor = lgetenv("EDITOR"); 16312296Sphk if (editor == NULL || *editor == '\0') 16412296Sphk editor = EDIT_PGM; 16512296Sphk } 16612296Sphk editproto = lgetenv("LESSEDIT"); 16712296Sphk if (editproto == NULL || *editproto == '\0') 16812296Sphk editproto = "%E ?lm+%lm. %f"; 16912296Sphk#endif 17012296Sphk 17118797Swollman /* 1721541Srgrimes * Call get_ifile with all the command line filenames 1731541Srgrimes * to "register" them with the ifile system. 1741541Srgrimes */ 1751541Srgrimes ifile = NULL_IFILE; 1761541Srgrimes if (dohelp) 1771541Srgrimes ifile = get_ifile(FAKE_HELPFILE, ifile); 1781541Srgrimes while (argc-- > 0) 1791541Srgrimes { 1801541Srgrimes char *filename; 1811541Srgrimes#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 1821541Srgrimes /* 1831541Srgrimes * Because the "shell" doesn't expand filename patterns, 1841541Srgrimes * treat each argument as a filename pattern rather than 1851541Srgrimes * a single filename. 1861541Srgrimes * Expand the pattern and iterate over the expanded list. 1871541Srgrimes */ 1881541Srgrimes struct textlist tlist; 1891541Srgrimes char *gfilename; 1901541Srgrimes 1911541Srgrimes gfilename = lglob(*argv++); 1921541Srgrimes init_textlist(&tlist, gfilename); 1931541Srgrimes filename = NULL; 1941541Srgrimes while ((filename = forw_textlist(&tlist, filename)) != NULL) 19514230Sphk { 19614230Sphk (void) get_ifile(filename, ifile); 19714230Sphk ifile = prev_ifile(NULL_IFILE); 19817758Ssos } 19917758Ssos free(gfilename); 20017758Ssos#else 20117758Ssos filename = shell_quote(*argv); 2021541Srgrimes if (filename == NULL) 2031541Srgrimes filename = *argv; 20412296Sphk argv++; 20512820Sphk (void) get_ifile(filename, ifile); 2061541Srgrimes ifile = prev_ifile(NULL_IFILE); 2071541Srgrimes#endif 2081541Srgrimes } 2091541Srgrimes /* 2101541Srgrimes * Set up terminal, etc. 21113929Swollman */ 21213929Swollman if (!is_tty) 2131541Srgrimes { 21415026Sphk /* 21515026Sphk * Output is not a tty. 21615026Sphk * Just copy the input file(s) to output. 21714232Sphk */ 2181541Srgrimes SET_BINARY(1); 2191541Srgrimes if (nifile() == 0) 2201541Srgrimes { 22118797Swollman if (edit_stdin() == 0) 2221541Srgrimes cat_file(); 2231541Srgrimes } else if (edit_first() == 0) 2241541Srgrimes { 2251541Srgrimes do { 2261541Srgrimes cat_file(); 2271541Srgrimes } while (edit_next(1) == 0); 2281541Srgrimes } 2291541Srgrimes quit(QUIT_OK); 23018797Swollman } 23118797Swollman 23218797Swollman if (missing_cap && !know_dumb && !more_mode) 23318797Swollman error("WARNING: terminal is not fully functional", NULL_PARG); 23418797Swollman init_mark(); 23518797Swollman open_getchr(); 23618797Swollman raw_mode(1); 23718797Swollman init_signals(1); 23818797Swollman 2391541Srgrimes /* 2401541Srgrimes * Select the first file to examine. 2411541Srgrimes */ 24213929Swollman#if TAGS 2431541Srgrimes if (tagoption != NULL || strcmp(tags, "-") == 0) 2441541Srgrimes { 24518797Swollman /* 24618797Swollman * A -t option was given. 2471541Srgrimes * Verify that no filenames were also given. 2481541Srgrimes * Edit the file selected by the "tags" search, 2491541Srgrimes * and search for the proper line in the file. 25018797Swollman */ 25118797Swollman if (nifile() > 0) 2521541Srgrimes { 2531541Srgrimes error("No filenames allowed with -t option", NULL_PARG); 2541541Srgrimes quit(QUIT_ERROR); 2551541Srgrimes } 2561541Srgrimes findtag(tagoption); 2571541Srgrimes if (edit_tagfile()) /* Edit file which contains the tag */ 2581541Srgrimes quit(QUIT_ERROR); 25913929Swollman /* 2601541Srgrimes * Search for the line which contains the tag. 2611541Srgrimes * Set up initial_scrpos so we display that line. 2621541Srgrimes */ 26318797Swollman initial_scrpos.pos = tagsearch(); 26418797Swollman if (initial_scrpos.pos == NULL_POSITION) 26518797Swollman quit(QUIT_ERROR); 26618797Swollman initial_scrpos.ln = jump_sline; 26718797Swollman } else 2683311Sphk#endif 2691541Srgrimes if (nifile() == 0) 2701541Srgrimes { 2711541Srgrimes if (edit_stdin()) /* Edit standard input */ 2721541Srgrimes quit(QUIT_ERROR); 2731541Srgrimes } else 2741541Srgrimes { 2751541Srgrimes if (edit_first()) /* Edit first valid file in cmd line */ 2761541Srgrimes quit(QUIT_ERROR); 2771541Srgrimes } 2781541Srgrimes 2791541Srgrimes init(); 2801541Srgrimes commands(); 2811541Srgrimes quit(QUIT_OK); 2821541Srgrimes /*NOTREACHED*/ 2831541Srgrimes return (0); 2841541Srgrimes} 2851541Srgrimes 2861541Srgrimes/* 2871541Srgrimes * Copy a string to a "safe" place 2881541Srgrimes * (that is, to a buffer allocated by calloc). 2891541Srgrimes */ 2901541Srgrimes public char * 29118797Swollmansave(s) 2921541Srgrimes char *s; 2931541Srgrimes{ 2941541Srgrimes register char *p; 2951541Srgrimes 2961541Srgrimes p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 2971541Srgrimes strcpy(p, s); 2981541Srgrimes return (p); 2991541Srgrimes} 3001541Srgrimes 3011541Srgrimes/* 3025543Sugen * Allocate memory. 3035543Sugen * Like calloc(), but never returns an error (NULL). 3045543Sugen */ 3055543Sugen public VOID_POINTER 3065543Sugenecalloc(count, size) 30717072Sjulian int count; 30817758Ssos unsigned int size; 3095543Sugen{ 3105543Sugen register VOID_POINTER p; 3115543Sugen 3121541Srgrimes p = (VOID_POINTER) calloc(count, size); 31318797Swollman if (p != NULL) 31417072Sjulian return (p); 31517072Sjulian error("Cannot allocate memory", NULL_PARG); 3163969Sjkh quit(QUIT_ERROR); 31717072Sjulian /*NOTREACHED*/ 31817072Sjulian return (NULL); 31917072Sjulian} 32017072Sjulian 32117072Sjulian/* 32217072Sjulian * Skip leading spaces in a string. 32317072Sjulian */ 32417072Sjulian public char * 32517072Sjulianskipsp(s) 32617072Sjulian register char *s; 32717072Sjulian{ 32817072Sjulian while (*s == ' ' || *s == '\t') 32917072Sjulian s++; 33017072Sjulian return (s); 33117072Sjulian} 33217072Sjulian 33317072Sjulian/* 33417072Sjulian * See how many characters of two strings are identical. 33519113Ssos * If uppercase is true, the first string must begin with an uppercase 33617758Ssos * character; the remainder of the first string may be either case. 33718797Swollman */ 33817758Ssos public int 3391541Srgrimessprefix(ps, s, uppercase) 3401541Srgrimes char *ps; 3411541Srgrimes char *s; 3421541Srgrimes int uppercase; 3431541Srgrimes{ 3441541Srgrimes register int c; 3451541Srgrimes register int sc; 3461541Srgrimes register int len = 0; 34713929Swollman 3481541Srgrimes for ( ; *s != '\0'; s++, ps++) 3492531Swollman { 3509209Swollman c = *ps; 3512531Swollman if (uppercase) 3522531Swollman { 3532531Swollman if (len == 0 && SIMPLE_IS_LOWER(c)) 3542531Swollman return (-1); 3559209Swollman if (SIMPLE_IS_UPPER(c)) 3562531Swollman c = SIMPLE_TO_LOWER(c); 3572531Swollman } 3581541Srgrimes sc = *s; 3591541Srgrimes if (len > 0 && SIMPLE_IS_UPPER(sc)) 3601541Srgrimes sc = SIMPLE_TO_LOWER(sc); 3611541Srgrimes if (c != sc) 3621541Srgrimes break; 3631541Srgrimes len++; 3641541Srgrimes } 3651541Srgrimes return (len); 36614817Sphk} 3671541Srgrimes 3681541Srgrimes/* 3691541Srgrimes * Exit the program. 3701541Srgrimes */ 3711541Srgrimes public void 3721541Srgrimesquit(status) 3731541Srgrimes int status; 3741541Srgrimes{ 3751541Srgrimes static int save_status; 3761541Srgrimes 3771541Srgrimes /* 3781541Srgrimes * Put cursor at bottom left corner, clear the line, 3791541Srgrimes * reset the terminal modes, and exit. 3801541Srgrimes */ 3811541Srgrimes if (status < 0) 3821541Srgrimes status = save_status; 3831541Srgrimes else 3841541Srgrimes save_status = status; 3851541Srgrimes quitting = 1; 3861541Srgrimes edit((char*)NULL); 3871541Srgrimes if (any_display && is_tty) 3881541Srgrimes clear_bot(); 3891541Srgrimes deinit(); 3902531Swollman flush(); 3911541Srgrimes raw_mode(0); 3921541Srgrimes#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 39313929Swollman /* 3941541Srgrimes * If we don't close 2, we get some garbage from 3951541Srgrimes * 2's buffer when it flushes automatically. 3961541Srgrimes * I cannot track this one down RB 3971541Srgrimes * The same bug shows up if we use ^C^C to abort. 3981541Srgrimes */ 3991541Srgrimes close(2); 4001541Srgrimes#endif 4011541Srgrimes#if WIN32 4021541Srgrimes SetConsoleTitle(consoleTitle); 4031541Srgrimes#endif 4041541Srgrimes close_getchr(); 4051541Srgrimes exit(status); 4061541Srgrimes} 4071541Srgrimes