/* 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 #include #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef VMS # include #endif #include #include #include #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