main.c revision 161478
11556Srgrimes/* $FreeBSD: head/contrib/less/main.c 161478 2006-08-20 15:50:51Z delphij $ */ 21556Srgrimes/* 31556Srgrimes * Copyright (C) 1984-2004 Mark Nudelman 41556Srgrimes * 51556Srgrimes * You may distribute under the terms of either the GNU General Public 61556Srgrimes * License or the Less License, as specified in the README file. 71556Srgrimes * 81556Srgrimes * For more information about less, or for information on how to 91556Srgrimes * contact the author, see the README file. 101556Srgrimes */ 111556Srgrimes 121556Srgrimes 131556Srgrimes/* 141556Srgrimes * Entry point, initialization, miscellaneous routines. 151556Srgrimes */ 161556Srgrimes 171556Srgrimes#include "less.h" 181556Srgrimes#if MSDOS_COMPILER==WIN32C 191556Srgrimes#include <windows.h> 201556Srgrimes#endif 211556Srgrimes 221556Srgrimespublic char * every_first_cmd = NULL; 231556Srgrimespublic int new_file; 241556Srgrimespublic int is_tty; 251556Srgrimespublic IFILE curr_ifile = NULL_IFILE; 261556Srgrimespublic IFILE old_ifile = NULL_IFILE; 271556Srgrimespublic struct scrpos initial_scrpos; 281556Srgrimespublic int any_display = FALSE; 291556Srgrimespublic POSITION start_attnpos = NULL_POSITION; 301556Srgrimespublic POSITION end_attnpos = NULL_POSITION; 311556Srgrimespublic int wscroll; 321556Srgrimespublic char * progname; 331556Srgrimespublic int quitting; 3420425Sstevepublic int secure; 351556Srgrimespublic int dohelp; 361556Srgrimespublic int more_mode = 0; 371556Srgrimes 381556Srgrimes#if LOGFILE 391556Srgrimespublic int logfile = -1; 4036150Scharnierpublic int force_logfile = FALSE; 4136150Scharnierpublic char * namelogfile = NULL; 4236150Scharnier#endif 431556Srgrimes 4499110Sobrien#if EDITOR 4599110Sobrienpublic char * editor; 461556Srgrimespublic char * editproto; 4717987Speter#endif 481556Srgrimes 4917987Speter#if TAGS 5017987Speterextern char * tags; 511556Srgrimesextern char * tagoption; 5217525Sacheextern int jump_sline; 5359214Simp#endif 5417525Sache 551556Srgrimes#ifdef WIN32 561556Srgrimesstatic char consoleTitle[256]; 571556Srgrimes#endif 581556Srgrimes 591556Srgrimesextern int missing_cap; 601556Srgrimesextern int know_dumb; 611556Srgrimes 6217987Speter 631556Srgrimes/* 641556Srgrimes * Entry point. 651556Srgrimes */ 661556Srgrimesint 671556Srgrimesmain(argc, argv) 6817987Speter int argc; 691556Srgrimes char *argv[]; 701556Srgrimes{ 711556Srgrimes IFILE ifile; 721556Srgrimes char *s; 7317987Speter extern char *__progname; 7420425Ssteve 751556Srgrimes#ifdef __EMX__ 761556Srgrimes _response(&argc, &argv); 771556Srgrimes _wildcard(&argc, &argv); 78200998Sjilles#endif 79221669Sjilles 801556Srgrimes progname = *argv++; 81213811Sobrien argc--; 82213811Sobrien 831556Srgrimes secure = 0; 841556Srgrimes s = lgetenv("LESSSECURE"); 851556Srgrimes if (s != NULL && *s != '\0') 861556Srgrimes secure = 1; 871556Srgrimes 881556Srgrimes#ifdef WIN32 891556Srgrimes if (getenv("HOME") == NULL) 901556Srgrimes { 911556Srgrimes /* 9217987Speter * If there is no HOME environment variable, 9390111Simp * try the concatenation of HOMEDRIVE + HOMEPATH. 9417987Speter */ 951556Srgrimes char *drive = getenv("HOMEDRIVE"); 961556Srgrimes char *path = getenv("HOMEPATH"); 971556Srgrimes if (drive != NULL && path != NULL) 981556Srgrimes { 9917525Sache char *env = (char *) ecalloc(strlen(drive) + 100221669Sjilles strlen(path) + 6, sizeof(char)); 1011556Srgrimes strcpy(env, "HOME="); 102200998Sjilles strcat(env, drive); 10320425Ssteve strcat(env, path); 10420425Ssteve putenv(env); 10520425Ssteve } 10620425Ssteve } 10720425Ssteve GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char)); 10820425Ssteve#endif /* WIN32 */ 10920425Ssteve 11020425Ssteve /* 11120425Ssteve * Process command line arguments and LESS environment arguments. 11220425Ssteve * Command line arguments override environment arguments. 11320425Ssteve */ 11420425Ssteve if (strcmp(__progname, "more") == 0) 11520425Ssteve more_mode = 1; 116220978Sjilles 117220978Sjilles is_tty = isatty(1); 118218306Sjilles get_term(); 1191556Srgrimes init_cmds(); 120215567Sjilles init_prompt(); 121215567Sjilles init_charset(); 1221556Srgrimes init_line(); 1231556Srgrimes init_cmdhist(); 1241556Srgrimes init_option(); 1251556Srgrimes 1261556Srgrimes if (more_mode) { 1271556Srgrimes scan_option("-E"); 1281556Srgrimes scan_option("-m"); 1291556Srgrimes scan_option("-G"); 1301556Srgrimes scan_option("-f"); 1311556Srgrimes s = lgetenv("MORE"); 1321556Srgrimes } else { 133200998Sjilles s = lgetenv("LESS"); 1341556Srgrimes } 1351556Srgrimes if (s != NULL) 1361556Srgrimes scan_option(save(s)); 1371556Srgrimes 1381556Srgrimes#define isoptstring(s) (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') 1391556Srgrimes while (argc > 0 && (isoptstring(*argv) || isoptpending())) 1401556Srgrimes { 1411556Srgrimes s = *argv++; 1421556Srgrimes argc--; 143206759Sjilles if (strcmp(s, "--") == 0) 144203576Sjilles break; 145203576Sjilles scan_option(s); 1461556Srgrimes } 1471556Srgrimes#undef isoptstring 1481556Srgrimes 1491556Srgrimes if (isoptpending()) 1501556Srgrimes { 15119240Ssteve /* 15219240Ssteve * Last command line option was a flag requiring a 15319240Ssteve * following string, but there was no following string. 15419240Ssteve */ 1558855Srgrimes nopendopt(); 1561556Srgrimes quit(QUIT_OK); 1571556Srgrimes } 15825471Ssteve 15917987Speter#if EDITOR 16017987Speter editor = lgetenv("VISUAL"); 16117987Speter if (editor == NULL || *editor == '\0') 16217987Speter { 1631556Srgrimes editor = lgetenv("EDITOR"); 1641556Srgrimes if (editor == NULL || *editor == '\0') 1651556Srgrimes editor = EDIT_PGM; 1661556Srgrimes } 167194128Sjilles editproto = lgetenv("LESSEDIT"); 1681556Srgrimes if (editproto == NULL || *editproto == '\0') 1691556Srgrimes editproto = "%E ?lm+%lm. %f"; 1701556Srgrimes#endif 1711556Srgrimes 1721556Srgrimes /* 1731556Srgrimes * Call get_ifile with all the command line filenames 17417987Speter * to "register" them with the ifile system. 17517987Speter */ 1761556Srgrimes ifile = NULL_IFILE; 1771556Srgrimes if (dohelp) 1781556Srgrimes ifile = get_ifile(FAKE_HELPFILE, ifile); 1791556Srgrimes while (argc-- > 0) 1801556Srgrimes { 1811556Srgrimes char *filename; 1821556Srgrimes#if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) 1831556Srgrimes /* 1841556Srgrimes * Because the "shell" doesn't expand filename patterns, 18590111Simp * treat each argument as a filename pattern rather than 18617987Speter * a single filename. 1871556Srgrimes * Expand the pattern and iterate over the expanded list. 1881556Srgrimes */ 1891556Srgrimes struct textlist tlist; 1901556Srgrimes char *gfilename; 1911556Srgrimes 1921556Srgrimes gfilename = lglob(*argv++); 1931556Srgrimes init_textlist(&tlist, gfilename); 1941556Srgrimes filename = NULL; 1951556Srgrimes while ((filename = forw_textlist(&tlist, filename)) != NULL) 1961556Srgrimes { 1971556Srgrimes (void) get_ifile(filename, ifile); 1981556Srgrimes ifile = prev_ifile(NULL_IFILE); 1991556Srgrimes } 200163085Sstefanf free(gfilename); 2011556Srgrimes#else 2021556Srgrimes filename = shell_quote(*argv); 2031556Srgrimes if (filename == NULL) 2041556Srgrimes filename = *argv; 2051556Srgrimes argv++; 2061556Srgrimes (void) get_ifile(filename, ifile); 2071556Srgrimes ifile = prev_ifile(NULL_IFILE); 2081556Srgrimes#endif 2091556Srgrimes } 2101556Srgrimes /* 2111556Srgrimes * Set up terminal, etc. 212199629Sjilles */ 2131556Srgrimes if (!is_tty) 2141556Srgrimes { 2151556Srgrimes /* 2161556Srgrimes * Output is not a tty. 2171556Srgrimes * Just copy the input file(s) to output. 2181556Srgrimes */ 2191556Srgrimes SET_BINARY(1); 2201556Srgrimes if (nifile() == 0) 22164702Scracauer { 222211349Sjilles if (edit_stdin() == 0) 223211349Sjilles cat_file(); 224211349Sjilles } else if (edit_first() == 0) 22520425Ssteve { 22620425Ssteve do { 2271556Srgrimes cat_file(); 22864702Scracauer } while (edit_next(1) == 0); 2291556Srgrimes } 2301556Srgrimes quit(QUIT_OK); 2311556Srgrimes } 2321556Srgrimes 2331556Srgrimes if (missing_cap && !know_dumb && !more_mode) 2341556Srgrimes error("WARNING: terminal is not fully functional", NULL_PARG); 2351556Srgrimes init_mark(); 2361556Srgrimes open_getchr(); 237213811Sobrien raw_mode(1); 238201053Sjilles init_signals(1); 23990111Simp 2401556Srgrimes /* 2411556Srgrimes * Select the first file to examine. 2421556Srgrimes */ 2431556Srgrimes#if TAGS 2441556Srgrimes if (tagoption != NULL || strcmp(tags, "-") == 0) 2451556Srgrimes { 2461556Srgrimes /* 2471556Srgrimes * A -t option was given. 2481556Srgrimes * Verify that no filenames were also given. 2491556Srgrimes * Edit the file selected by the "tags" search, 2501556Srgrimes * and search for the proper line in the file. 2511556Srgrimes */ 2521556Srgrimes if (nifile() > 0) 2531556Srgrimes { 2541556Srgrimes error("No filenames allowed with -t option", NULL_PARG); 2551556Srgrimes quit(QUIT_ERROR); 2561556Srgrimes } 2571556Srgrimes findtag(tagoption); 2581556Srgrimes if (edit_tagfile()) /* Edit file which contains the tag */ 259200956Sjilles quit(QUIT_ERROR); 26017987Speter /* 2611556Srgrimes * Search for the line which contains the tag. 2621556Srgrimes * Set up initial_scrpos so we display that line. 2631556Srgrimes */ 2641556Srgrimes initial_scrpos.pos = tagsearch(); 2651556Srgrimes if (initial_scrpos.pos == NULL_POSITION) 2661556Srgrimes quit(QUIT_ERROR); 26753891Scracauer initial_scrpos.ln = jump_sline; 2681556Srgrimes } else 2691556Srgrimes#endif 2701556Srgrimes if (nifile() == 0) 2711556Srgrimes { 2721556Srgrimes if (edit_stdin()) /* Edit standard input */ 2731556Srgrimes quit(QUIT_ERROR); 2741556Srgrimes } else 2751556Srgrimes { 27646684Skris if (edit_first()) /* Edit first valid file in cmd line */ 27717987Speter quit(QUIT_ERROR); 2781556Srgrimes } 2791556Srgrimes 28017987Speter init(); 281213811Sobrien commands(); 28290111Simp quit(QUIT_OK); 28317987Speter /*NOTREACHED*/ 28417987Speter return (0); 285200956Sjilles} 28617987Speter 28717987Speter/* 28817987Speter * Copy a string to a "safe" place 28917987Speter * (that is, to a buffer allocated by calloc). 29017987Speter */ 29117987Speter public char * 29217987Spetersave(s) 293222173Sjilles char *s; 294222173Sjilles{ 295222173Sjilles register char *p; 296222173Sjilles 297222173Sjilles p = (char *) ecalloc(strlen(s)+1, sizeof(char)); 298222173Sjilles strcpy(p, s); 299222173Sjilles return (p); 30017987Speter} 30117987Speter 30217987Speter/* 30317987Speter * Allocate memory. 30417987Speter * Like calloc(), but never returns an error (NULL). 30517987Speter */ 30690111Simp public VOID_POINTER 30717987Speterecalloc(count, size) 308208630Sjilles int count; 309157414Sstefanf unsigned int size; 310157414Sstefanf{ 311157414Sstefanf register VOID_POINTER p; 312157414Sstefanf 3131556Srgrimes p = (VOID_POINTER) calloc(count, size); 31417987Speter if (p != NULL) 315208630Sjilles return (p); 316208630Sjilles error("Cannot allocate memory", NULL_PARG); 317208630Sjilles quit(QUIT_ERROR); 318208630Sjilles /*NOTREACHED*/ 319208630Sjilles return (NULL); 320208630Sjilles} 321208630Sjilles 322157414Sstefanf/* 323157414Sstefanf * Skip leading spaces in a string. 324157414Sstefanf */ 325157414Sstefanf public char * 3261556Srgrimesskipsp(s) 3271556Srgrimes register char *s; 3281556Srgrimes{ 3291556Srgrimes while (*s == ' ' || *s == '\t') 33017987Speter s++; 33190111Simp return (s); 33217987Speter} 3331556Srgrimes 33417987Speter/* 33520425Ssteve * See how many characters of two strings are identical. 336217175Sjilles * If uppercase is true, the first string must begin with an uppercase 33720425Ssteve * character; the remainder of the first string may be either case. 338217175Sjilles */ 3391556Srgrimes public int 340sprefix(ps, s, uppercase) 341 char *ps; 342 char *s; 343 int uppercase; 344{ 345 register int c; 346 register int sc; 347 register int len = 0; 348 349 for ( ; *s != '\0'; s++, ps++) 350 { 351 c = *ps; 352 if (uppercase) 353 { 354 if (len == 0 && ASCII_IS_LOWER(c)) 355 return (-1); 356 if (ASCII_IS_UPPER(c)) 357 c = ASCII_TO_LOWER(c); 358 } 359 sc = *s; 360 if (len > 0 && ASCII_IS_UPPER(sc)) 361 sc = ASCII_TO_LOWER(sc); 362 if (c != sc) 363 break; 364 len++; 365 } 366 return (len); 367} 368 369/* 370 * Exit the program. 371 */ 372 public void 373quit(status) 374 int status; 375{ 376 static int save_status; 377 378 /* 379 * Put cursor at bottom left corner, clear the line, 380 * reset the terminal modes, and exit. 381 */ 382 if (status < 0) 383 status = save_status; 384 else 385 save_status = status; 386 quitting = 1; 387 edit((char*)NULL); 388 save_cmdhist(); 389 if (any_display && is_tty) 390 clear_bot(); 391 deinit(); 392 flush(); 393 raw_mode(0); 394#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC 395 /* 396 * If we don't close 2, we get some garbage from 397 * 2's buffer when it flushes automatically. 398 * I cannot track this one down RB 399 * The same bug shows up if we use ^C^C to abort. 400 */ 401 close(2); 402#endif 403#if WIN32 404 SetConsoleTitle(consoleTitle); 405#endif 406 close_getchr(); 407 exit(status); 408} 409