566 lines
13 KiB
C
566 lines
13 KiB
C
/*
|
|
This file is part of MOST.
|
|
|
|
Copyright (c) 1991, 1999, 2002, 2005-2018, 2019 John E. Davis
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 2 of the License, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program; if not, write to the Free Software Foundation, Inc., 675
|
|
Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
# include <stdlib.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#ifdef VMS
|
|
# include <rmsdef.h>
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
|
|
#include <slang.h>
|
|
#include "version.h"
|
|
|
|
#include "jdmacros.h"
|
|
|
|
#include "most.h"
|
|
#include "search.h"
|
|
#include "window.h"
|
|
#include "file.h"
|
|
#include "sysdep.h"
|
|
#include "keym.h"
|
|
#include "display.h"
|
|
#include "line.h"
|
|
|
|
int Most_S_Opt = 0; /* squeeze liness */
|
|
int Most_A_Opt = 1; /* automatically choose -b if necessary */
|
|
int Most_V_Opt = 0; /* display control chars */
|
|
int Most_B_Opt = 0; /* display Binary File */
|
|
int Most_T_Opt = 0; /* display tab as ^I-- valid only with V option */
|
|
int Most_D_Opt = 0; /* delete file mode (see ':D') */
|
|
int Most_K_Opt = 0; /* Display 8 bit unformatted (Kanji) */
|
|
int Most_Z_Opt = 0; /* Gunzip on the fly */
|
|
int Most_Want_Exit;
|
|
int Most_Secure_Mode;
|
|
int Most_Captive_Mode;
|
|
#if MOST_HAS_MMAP
|
|
int Most_Disable_MMap = 0;
|
|
#endif
|
|
int Most_Do_Regexp_Search = 0;
|
|
|
|
int Most_UTF8_Mode = -1; /* -1:auto, 0:off, 1:on */
|
|
|
|
static int Most_Starting_Line;
|
|
char *Most_Program; /* Program Name (argv[0]) */
|
|
|
|
static char *Most_Version = MOST_VERSION_STR;
|
|
|
|
#ifdef VMS
|
|
# ifndef isalpha
|
|
# define isalpha(x) \
|
|
(((x >= 'A') && (x <= 'Z'))||((x >= 'a') && (x <= 'z')) ? 1 : 0)
|
|
# endif
|
|
#endif
|
|
|
|
void most_usage (void)
|
|
{
|
|
fprintf(stderr,"MOST version %s (S-Lang version %s)\n",
|
|
Most_Version, SLang_Version_String);
|
|
if (SLang_Version != SLANG_VERSION)
|
|
fprintf (stderr, " *Note: This executable was compiled against S-Lang %s\n", SLANG_VERSION_STRING);
|
|
|
|
fprintf (stderr, "Usage:\n");
|
|
fprintf(stderr, "most [-1Cbcdkrstvw] [+/string] [+line number] [+s] [+d] file...\n");
|
|
fputs(" where: -1: assume VT100 terminal. (VMS only)\n", stderr);
|
|
fputs(" -b: Startup in binary mode.\n", stderr);
|
|
fputs(" -C: disable color support\n", stderr);
|
|
fputs(" -c: Make searches case sensitive.\n", stderr);
|
|
fputs(" -d: Do not display the \\ wrap marker when wrapping lines.\n", stderr);
|
|
/* fputs(" -k: Kanji mode.\n", stderr); */
|
|
#if MOST_HAS_MMAP
|
|
fputs(" -M: Do not attempt to mmap files.\n", stderr);
|
|
#endif
|
|
fputs(" -r: Default to regexp search\n", stderr);
|
|
fputs(" -s: Squeeze out excess blank lines.\n", stderr);
|
|
fputs(" -t: Display tabs as ^I. If this option is immediately followed\n", stderr);
|
|
fputs(" by an integer, the integer sets the tab width.\n", stderr);
|
|
fputs(" -u: Disable UTF-8 mode\n", stderr);
|
|
fputs(" -v: Do not interpret backspace formatting characters.\n", stderr);
|
|
fputs(" -w: Wrap lines.\n", stderr);
|
|
fputs(" -z: No gunzip-on-the-fly.\n", stderr);
|
|
fputs(" +/string:\n", stderr);
|
|
fputs(" Search for string\n", stderr);
|
|
fputs(" +line number\n", stderr);
|
|
fputs(" Start up at specified line number.\n", stderr);
|
|
fputs(" +d: Allow file deletion.\n", stderr);
|
|
fputs(" +s: Secure Mode-- no edit, cd, shell, and reading files not\n", stderr);
|
|
fputs(" already listed on the command line.\n", stderr);
|
|
fputs(" +u: Enable UTF-8 mode.\n", stderr);
|
|
fprintf(stderr, "\nExample: most -ct4 +82 keymap.c\n");
|
|
fputs(" makes searches case sensitive, sets tabwidth to 4, and displays the file\n", stderr);
|
|
fputs(" keymap.c starting at line 82.\n", stderr);
|
|
}
|
|
|
|
static void do_switches(char *str);
|
|
|
|
static void do_extended_switches(char *str)
|
|
{
|
|
int i;
|
|
char ch;
|
|
char numstr [256];
|
|
|
|
i = 0;
|
|
ch = *(++str);
|
|
if ( ch == '/')
|
|
{
|
|
strcpy (Most_Search_Str,++str);
|
|
return;
|
|
}
|
|
|
|
if (ch >= '0' && ch <= '9')
|
|
{
|
|
while ((ch >= '0' && ch <= '9') && (i < 10))
|
|
{
|
|
numstr[i++] = ch;
|
|
ch = *(++str);
|
|
}
|
|
numstr[i] = '\0';
|
|
if (1 == sscanf (numstr,"%d", &i))
|
|
Most_Starting_Line = i;
|
|
return;
|
|
}
|
|
|
|
if (isalpha(ch))
|
|
{
|
|
while (1)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case 0:
|
|
return;
|
|
case ' ':
|
|
case '+':
|
|
break;
|
|
case '-':
|
|
do_switches (str);
|
|
return;
|
|
|
|
case 'D':
|
|
case 'd':
|
|
Most_D_Opt = 1; /* delete file mode */
|
|
break;
|
|
case 'S':
|
|
case 's':
|
|
Most_Secure_Mode = 1;
|
|
break;
|
|
|
|
case 'U':
|
|
case 'u':
|
|
Most_UTF8_Mode = 1; /* +u */
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr,"%s invalid extended option %c ignored.\n",
|
|
Most_Program, ch);
|
|
}
|
|
ch = *(++str);
|
|
}
|
|
}
|
|
|
|
fprintf(stderr,"%s: switch '+%s' not valid.\n", Most_Program, str);
|
|
exit (1);
|
|
}
|
|
|
|
/* if non-zero, assume terminal is only a generic vt100 */
|
|
static int assume_vt100 = 0;
|
|
static int No_Colors = 0;
|
|
|
|
static void do_switches(char *str)
|
|
{
|
|
char ch;
|
|
if (*str == '-') str++;
|
|
while ((ch = *str++) != '\0')
|
|
{
|
|
switch (ch)
|
|
{
|
|
default:
|
|
fprintf(stderr,"%s: invalid switch %c ignored.\n",
|
|
Most_Program, ch);
|
|
break;
|
|
|
|
case 'C':
|
|
No_Colors = 1;
|
|
break;
|
|
case 'c':
|
|
Most_Case_Sensitive = 1;
|
|
break;
|
|
case 'd':
|
|
case 'D':
|
|
Most_Show_Wrap_Marker = 0;
|
|
break;
|
|
case 'r':
|
|
Most_Do_Regexp_Search = 1;
|
|
break;
|
|
case 's':
|
|
case 'S':
|
|
Most_S_Opt = 1; break;
|
|
case 'V':
|
|
case 'v':
|
|
Most_V_Opt = 1; /* verbose-- convert control chars to '^' 'ch' */
|
|
break;
|
|
case 'W':
|
|
case 'w': Most_W_Opt = 1; break;
|
|
|
|
case 'K': /* Kanji option */
|
|
case 'k':
|
|
/* Most_K_Opt = 1; break; */
|
|
break;
|
|
|
|
case 'B':
|
|
case 'b':
|
|
Most_B_Opt = 1; /* Binary display 8 bit */
|
|
break;
|
|
|
|
case 'M':
|
|
#if MOST_HAS_MMAP
|
|
Most_Disable_MMap = 1;
|
|
#endif
|
|
break;
|
|
|
|
case 'z':
|
|
case 'Z':
|
|
Most_Z_Opt = 1; /* NO Gunzip-on-the-fly */
|
|
break;
|
|
|
|
case 't':
|
|
case 'T': /* expand tabs to '^I'; meaningful only with 'v' */
|
|
ch = *str;
|
|
if ((ch <= '9') && (ch >= '0'))
|
|
{
|
|
str++;
|
|
Most_Tab_Width = (int) ch - '0';
|
|
if (Most_Tab_Width == 0) Most_T_Opt = 1;
|
|
}
|
|
else Most_T_Opt = 1;
|
|
break;
|
|
|
|
case 'n': case 'N':
|
|
/* could be the Gopher Naive user switch --- ignored. */
|
|
break;
|
|
case '1': assume_vt100 = 1;
|
|
break;
|
|
|
|
case 'u':
|
|
case 'U':
|
|
Most_UTF8_Mode = 0; /* -u */
|
|
break;
|
|
|
|
/* Allow MOST_SWITCHES environment variable to contain + forms,
|
|
* e.g., "-sn+d" or "-s -n +d"
|
|
*/
|
|
case ' ':
|
|
case '-':
|
|
break;
|
|
case '+':
|
|
do_extended_switches (str - 1); /* include '+' */
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void most_exit_error(char *fmt,...)
|
|
{
|
|
va_list ap;
|
|
|
|
most_reset_tty ();
|
|
most_reset_display();
|
|
if (fmt != NULL)
|
|
{
|
|
va_start (ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end (ap);
|
|
putc ('\n', stderr);
|
|
}
|
|
#ifdef MALLOC_DEBUG
|
|
SLmalloc_dump_statistics ();
|
|
#endif
|
|
exit(1);
|
|
}
|
|
|
|
static void play_cat(char *file)
|
|
{
|
|
char buf[4096 * 4];
|
|
int n;
|
|
FILE *fp;
|
|
|
|
if (file == NULL) fp = stdin;
|
|
else
|
|
{
|
|
fp = fopen(file, "r");
|
|
if (fp == NULL) return;
|
|
}
|
|
|
|
while ((n = fread(buf, 1, 4096 * 4, fp)) > 0)
|
|
{
|
|
int m;
|
|
m = fwrite (buf, 1, n, stdout);
|
|
if (m != n)
|
|
{
|
|
fprintf (stderr, "fwrite returned %d, errno = %d\n",
|
|
m, errno);
|
|
(void) fclose (fp);
|
|
exit (1);
|
|
}
|
|
}
|
|
(void) fclose (fp);
|
|
}
|
|
|
|
void most_initialize_most (void)
|
|
{
|
|
Most_S_Opt = 0;
|
|
Most_A_Opt = 1;
|
|
Most_V_Opt = 0;
|
|
Most_B_Opt = 0;
|
|
Most_T_Opt = 0;
|
|
Most_D_Opt = 0;
|
|
Most_K_Opt = 0;
|
|
Most_W_Opt = 0;
|
|
|
|
Most_Selective_Display = 0;
|
|
*Most_Search_Str = 0; Most_Search_Dir = 1;
|
|
Most_Top_Win = Most_Win = NULL;
|
|
Most_Buf = NULL;
|
|
Most_Eob = NULL;
|
|
Most_Beg = NULL;
|
|
Most_Captive_Mode = Most_Secure_Mode = 0;
|
|
Most_Want_Exit = 0;
|
|
}
|
|
|
|
static void do_most (char *file, int start)
|
|
{
|
|
MOST_INT row, col;
|
|
|
|
most_get_cdir(Most_C_Dir);
|
|
|
|
row = col = 0;
|
|
|
|
if ((-1 == most_find_file (file))
|
|
&& (Most_Num_Files == 1))
|
|
most_exit_error ("%s: failed to open for reading.", file);
|
|
|
|
most_init_display ();
|
|
|
|
most_goto_line(start);
|
|
|
|
Most_Curs_Offset = Most_C_Offset;
|
|
|
|
if (*Most_Search_Str
|
|
&& ((row = most_search (Most_Beg + Most_C_Offset, 1, &col)) > 0))
|
|
most_goto_line(row);
|
|
else
|
|
{
|
|
row = Most_C_Line;
|
|
col = 1;
|
|
}
|
|
|
|
most_window_buffer();
|
|
Most_Curs_Row = Most_Win->curs_line = row - Most_C_Line + 1;
|
|
Most_Win->curs_offset = Most_Curs_Offset;
|
|
Most_Curs_Col = Most_Win->curs_col = col;
|
|
most_redraw_window();
|
|
most_update_status();
|
|
|
|
while (Most_Want_Exit == 0)
|
|
{
|
|
most_execute_key();
|
|
}
|
|
}
|
|
|
|
void most_exit_most (void)
|
|
{
|
|
if (Most_Want_Exit) return;
|
|
Most_Want_Exit = 1;
|
|
most_clear_minibuffer ();
|
|
most_reset_tty ();
|
|
most_reset_display ();
|
|
most_free_windows ();
|
|
#ifdef MALLOC_DEBUG
|
|
SLmalloc_dump_statistics ();
|
|
#endif
|
|
}
|
|
|
|
static void utf8_config (void)
|
|
{
|
|
int utf8_mode = Most_UTF8_Mode;
|
|
|
|
utf8_mode = SLutf8_enable (-1); /* returns 0 or 1 */
|
|
if (Most_UTF8_Mode == -1)
|
|
Most_UTF8_Mode = utf8_mode;
|
|
else if (utf8_mode != Most_UTF8_Mode)
|
|
{
|
|
if (utf8_mode == 1)
|
|
(void) SLsmg_utf8_enable (0); /* locale is UTF-8, but -u passed */
|
|
else
|
|
(void) SLsmg_utf8_enable (1); /* locale not UTF-8, but +u passed */
|
|
}
|
|
}
|
|
|
|
int most (int argc, char **argv)
|
|
{
|
|
char file[MAX_PATHLEN], *switches;
|
|
int file_i = 0, quit,i,piped;
|
|
int status = 0;
|
|
|
|
#ifdef VMS
|
|
char filename[256];
|
|
#else
|
|
int j;
|
|
#endif
|
|
|
|
Most_Program = argv[0];
|
|
piped = 0;
|
|
|
|
switches = getenv ("MOST_PROMPT");
|
|
if ((switches != NULL) && (*switches != 0)) Most_Global_Msg = switches;
|
|
|
|
switches = getenv("MOST_SWITCHES");
|
|
if (switches != NULL) do_switches(switches);
|
|
|
|
i = 1;
|
|
if (argc > 1)
|
|
{
|
|
quit = 0;
|
|
while ((!quit) && (i < argc))
|
|
{
|
|
if (argv[i][0] == '-')
|
|
do_switches(argv[i++]);
|
|
else if (argv[i][0] == '+')
|
|
do_extended_switches(argv[i++]);
|
|
else quit = 1;
|
|
}
|
|
}
|
|
|
|
#if MOST_HAS_MMAP
|
|
/* if (Most_D_Opt) */
|
|
/* Most_Disable_MMap = 1; */
|
|
#endif
|
|
|
|
if (i == argc)
|
|
{
|
|
if (isatty(0)) /* 1 if stdin is a terminal, 0 otherwise */
|
|
{
|
|
most_usage ();
|
|
return 0;
|
|
}
|
|
/* assume input is from stdin */
|
|
file[0] = '\0'; /* tells most this is stdin */
|
|
piped = 1;
|
|
if (!isatty(fileno(stdout)))
|
|
{
|
|
play_cat(NULL);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strncpy (file, argv[i], sizeof(file));
|
|
file[sizeof(file)-1] = 0;
|
|
}
|
|
|
|
if (!isatty(fileno(stdout)))
|
|
{
|
|
while (i < argc) play_cat(argv[i++]);
|
|
exit(0);
|
|
}
|
|
|
|
Most_Num_Files = 0;
|
|
|
|
SLtt_get_terminfo();
|
|
utf8_config ();
|
|
SLtt_Ignore_Beep = 1;
|
|
if (No_Colors)
|
|
SLtt_Use_Ansi_Colors = 0;
|
|
|
|
most_setup_colors ();
|
|
most_init_tty ();
|
|
most_init_keymaps ();
|
|
|
|
if (Most_B_Opt) Most_A_Opt = 0; /* explicit b overrides a */
|
|
|
|
if (!piped)
|
|
{
|
|
file_i = i;
|
|
#ifdef VMS
|
|
while(i < argc)
|
|
{
|
|
if (Most_Num_Files >= MOST_MAX_FILES) break;
|
|
if (argv[i][0] == '.') strcpy(file,"*"); else *file = 0;
|
|
strcat(file, most_unix2vms(argv[i++]));
|
|
while (RMS$_NORMAL == (status = most_expand_file_name(file,filename)))
|
|
{
|
|
Most_File_Ring[Most_Num_Files] = (char*) MOSTMALLOC(strlen(filename) + 1);
|
|
strcpy(Most_File_Ring[Most_Num_Files++], filename);
|
|
}
|
|
if (status == RMS$_NMF) status = RMS$_NORMAL; /* avoid spurious warning message */
|
|
}
|
|
|
|
if (Most_Num_Files) strcpy(file,Most_File_Ring[0]);
|
|
else fputs("%%MOST-W-NOFILES, no files found\n", stderr);
|
|
#else
|
|
Most_Num_Files = argc - i;
|
|
if (Most_Num_Files > MOST_MAX_FILES)
|
|
{
|
|
Most_Num_Files = MOST_MAX_FILES;
|
|
argc = Most_Num_Files + i;
|
|
}
|
|
|
|
j = 0;
|
|
while (i < argc)
|
|
{
|
|
Most_File_Ring[j++] = argv[i++];
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (Most_Num_Files || piped) do_most(file, Most_Starting_Line);
|
|
else if (Most_Num_Files == 0)
|
|
fprintf(stderr,"File %s not found\n", argv[file_i]);
|
|
|
|
most_exit_most ();
|
|
return status;
|
|
}
|
|
|
|
#if SLANG_VERSION <= 10409
|
|
|
|
int SLang_set_error (int x)
|
|
{
|
|
SLang_Error = x;
|
|
return 0;
|
|
}
|
|
|
|
int SLang_get_error (void)
|
|
{
|
|
return SLang_Error;
|
|
}
|
|
|
|
#endif
|