rust-most/vendor/most-5.1.0/src/most.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