rust-most/vendor/most-5.1.0/src/file.c

847 lines
16 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 <string.h>
#include <ctype.h>
#include <errno.h>
#ifndef VMS
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif
#else
# include <types.h>
# include <stat.h>
#endif /* NOT VMS */
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <slang.h>
#include "jdmacros.h"
#ifndef O_RDONLY
# define O_RDONLY 0
#endif
#include "window.h"
#include "file.h"
#include "most.h"
#include "buffer.h"
#include "display.h"
#include "sysdep.h"
#include "edit.h"
char *Most_File_Ring[MOST_MAX_FILES];
char Most_C_Dir[MAX_PATHLEN]; /* current working dir */
int Most_Num_Files;
int Most_Tail_Mode = 1;
#if !defined(VMS)
static int create_gunzip_cmd (char *cmd, char *file, char *buf, unsigned int sizeof_buf)
{
char *efile;
if (NULL == (efile = most_escape_filename (file, '"')))
return -1;
(void) _pSLsnprintf (buf, sizeof_buf, cmd, efile);
SLfree (efile);
return 0;
}
static int open_compressed_file(char *file, int mode, int *size)
{
int fd;
char buf[4], cmdbuf[2*MAX_PATHLEN];
struct stat st;
# ifdef O_BINARY
mode |= O_BINARY;
# endif
# ifdef IBMPC_SYSTEM
Most_Z_Opt = 1;
# endif
if (Most_Z_Opt)
{
if (stat(file, &st)) return(-1);
*size = st.st_size;
return (open(file,mode));
}
fd = open(file, O_RDONLY);
if (fd < 0) return fd;
if (4 == read(fd, buf, 4))
{
char *cmd = NULL;
if ((buf[0] == (char) 0x1f)
&& (buf[1] == (char) 0x8b)
&& (buf[2] == (char) 0x08)
&& ((buf[3] == (char) 0x08) || (buf[3] == (char)0x00)))
{
cmd = MOST_GUNZIP_POPEN_FORMAT;
}
else if ((buf[0] == 'B') && (buf[1] == 'Z') && (buf[2] == 'h')
&& (buf[3] > 47))
{
cmd = MOST_BZIP2_POPEN_FORMAT;
}
if (cmd != NULL)
{
FILE *fp;
close (fd);
most_flush_message ("Uncompressing file...");
if (-1 == create_gunzip_cmd (cmd, file, cmdbuf, sizeof(cmdbuf)))
return -1;
fp = popen (cmdbuf, "r"); /* GLIBC doe not support "rb" */
if (fp == NULL)
return -1;
*size = 0;
fd = fileno (fp);
Most_Buf->fp = fp;
/* pclose (fp); */
return fd;
}
}
close (fd);
if (stat(file, &st)) return(-1);
*size = st.st_size;
return (open(file,mode));
}
#endif /* VMS */
#if MOST_HAS_MMAP
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#ifndef MAP_FAILED
# define MAP_FAILED -1
#endif
static int try_mmap_buffer (int fd)
{
unsigned char *addr;
struct stat st;
Most_Buf->is_mmaped = 0;
if (Most_Disable_MMap)
return -1;
if (-1 == fstat (fd, &st))
return -1;
addr = (unsigned char *)mmap (NULL,st.st_size,PROT_READ,MAP_SHARED,fd,0);
if (addr == (unsigned char *)MAP_FAILED)
return -1;
Most_Buf->fd = fd;
Most_Eob = Most_Beg = Most_Buf->end = Most_Buf->beg = addr;
Most_Buf->size = 0;
Most_Buf->mmap_size = st.st_size;
Most_Buf->is_mmaped = 1;
return 0;
}
static int unmmap_buffer (Most_Buffer_Type *b)
{
if (b->is_mmaped == 0)
return 0;
if (b->beg != NULL)
munmap ((char *)b->beg, b->size);
b->end = b->beg = NULL;
if (b == Most_Buf)
{
Most_Beg = Most_Eob = NULL;
Most_C_Line = 0;
Most_Num_Lines = Most_C_Line = 0;
}
return 0;
}
static int resync_mmap (void)
{
struct stat st;
int line = Most_C_Line;
if (Most_Buf->fd == -1)
return 0;
if (-1 == fstat (Most_Buf->fd, &st))
return -1;
if ((unsigned int) st.st_size == Most_Buf->mmap_size)
return 0;
(void) unmmap_buffer (Most_Buf);
if (-1 == try_mmap_buffer (Most_Buf->fd))
return -1;
most_goto_line (line);
return 0;
}
#endif /* MOST_HAS_MMAP */
int most_close_buffer_file (Most_Buffer_Type *b)
{
if (b->fd != -1)
{
#if !defined(VMS)
if (b->fp != NULL) pclose (b->fp);
else
#endif
close(b->fd);
}
#if MOST_HAS_MMAP
unmmap_buffer (b);
#endif
if (b->beg != NULL)
SLFREE(b->beg);
b->beg = NULL;
b->fd = -1;
return 0;
}
/* If file[0] == 0, the file represents stdin */
static int insert_file(char *file)
{
int size = 0, fd;
/* int mode; */
#ifdef VMS
struct stat st;
unsigned recsz = 512;
/* extern int stat(char *, struct stat *); */
#endif
if (file[0] == '\0') /* assume stdin */
{
fd = 0;
strcpy (Most_Buf->file, "*stdin*");
}
else
{
#ifdef VMS
if (stat(file, &st)) return(-1);
/* mode = st.st_mode & S_IFMT; */
size = st.st_size;
recsz = st.st_fab_mrs;
if (recsz <= 255) recsz = 255;
/* VMS share options (shr=put) suggested by Henk D. Davids <hdavids@mswe.dnet.ms.philips.nl> */
/* VMS share options (shr=upi,get,put) suggested by Mark Pizzolato <mark@infocomm.com> */
fd = open(file,O_RDONLY,"ctx=rec","mbf=8","mbc=16","rop=RAH","shr=upi,get,put");
/* if (fd < 0) fd = open(file,O_RDONLY); */
#else
fd = open_compressed_file(file, O_RDONLY, &size);
# if MOST_HAS_MMAP
if (0 == try_mmap_buffer (fd))
return most_read_file_dsc (1, 1);
# endif
#endif
}
if (fd < 0) return(-1);
if (!fd || (size <= 0)) size = 0x7FFF;
#ifdef VMS
Most_Buf->rec = recsz;
#endif
Most_Buf->fd = fd;
/* This will fail on really large files. */
Most_Eob = Most_Beg = Most_Buf->beg = (unsigned char *) MOSTMALLOC(size);
Most_Buf->size = size;
return most_read_file_dsc (1, 1);
}
static void update_buffer_windows (Most_Buffer_Type *b)
{
Most_Window_Type *w;
if (NULL == (w = Most_Win))
return;
do
{
if (w->buf == b) w->dirty_flag = 1;
w = w->next;
}
while (w != Most_Win);
}
static void examine_file_contents (void)
{
unsigned char *pos, *pos_max;
if (Most_B_Opt || Most_K_Opt)
return;
pos = Most_Beg;
pos_max = pos + 512;
if (pos_max > Most_Eob)
pos_max = Most_Eob;
while (pos < pos_max)
{
if (0 == *pos)
{
Most_B_Opt = 1;
break;
}
pos++;
}
/* Check for a FITS file. The header looks like ASCII. */
if (Most_B_Opt == 0)
{
pos = Most_Beg;
pos_max = Most_Eob;
if ((pos_max > pos + 80)
&& (0 == strncmp ((char *) pos, "SIMPLE =", 9)))
{
Most_V_Opt = 1;
Most_W_Opt = 1;
}
}
}
static int First_Time_Hack = 0; /* true if reading file for first time */
#if MOST_HAS_MMAP
static int read_mmap_file_dsc (int many, int count_lines)
{
unsigned int size;
size = Most_Buf->size;
if (many == -1)
{
if (-1 == resync_mmap ())
return -1;
}
if (size == Most_Buf->mmap_size)
return 0;
if (many < 0)
size = Most_Buf->mmap_size;
else
{
size += many * 0xFFFF;
if (size > Most_Buf->mmap_size)
size = Most_Buf->mmap_size;
}
Most_Eob = Most_Buf->end = Most_Buf->beg + size;
Most_Buf->size = size;
most_flush_message ("Mapping file...");
if (First_Time_Hack)
examine_file_contents ();
if (count_lines)
Most_Num_Lines = most_count_lines (Most_Beg, Most_Eob);
most_message(Most_Global_Msg, 0);
return 1;
}
#endif
/* if read something, return non zero (1) */
int most_read_file_dsc (int many, int count_lines)
{
int fd = Most_Buf->fd, n = 0, i;
int dsize, size, passes = 0;
unsigned char *pos;
#ifdef VMS
int recsz = Most_Buf->rec;
#endif
if (fd < 0) return 0;
#if MOST_HAS_MMAP
if (Most_Buf->is_mmaped)
{
int ret = read_mmap_file_dsc (many, count_lines);
if (-1 != ret)
return ret;
if (Most_Buf->is_mmaped)
return -1;
/* No longer mapped..... */
}
#endif
dsize = 0x3FFF;
while (many--)
{
passes++;
most_flush_message ("Reading...");
size = (Most_Eob - Most_Beg) + dsize;
if (Most_Buf->size > size) pos = Most_Beg;
else
{
size = Most_Buf->size + 0xFFFF;
pos = (unsigned char *) MOSTREALLOC(Most_Beg, (unsigned) size);
Most_Buf->size = size;
}
Most_Eob = pos + (unsigned int) (Most_Eob - Most_Beg);
Most_Beg = pos;
pos = Most_Eob;
n = 0;
while (1)
{
#ifdef VMS
i = read (fd, (char *) pos, recsz);
#else
i = read (fd, (char *) pos, dsize - n);
#endif
if (i == -1)
{
#ifdef EINTR
if ((errno == EINTR) && (SLKeyBoard_Quit == 0)) continue;
#endif
break;
}
if (i == 0)
{
/* EOF */
/* Under linux, for some reason bash when invoked by
* man will reset the terminal. Apparantly this is a
* result of most being orphaned.
*/
#ifdef __unix__
if (fd == 0)
(void) most_reinit_terminal ();
#endif
break;
}
n += i;
pos += i;
if (n >= dsize)
break;
}
Most_Eob = Most_Buf->end = pos;
Most_Buf->beg = Most_Beg;
if (n != 0) n = 1;
if ((i <= 0)
|| SLKeyBoard_Quit)
{
break;
}
}
if (First_Time_Hack)
examine_file_contents ();
if (count_lines
&& (n || First_Time_Hack))
Most_Num_Lines = most_count_lines (Most_Beg, Most_Eob);
update_buffer_windows (Most_Buf);
most_message("reading...done", 0);
most_put_message();
most_message(Most_Global_Msg, 0);
return n;
}
/* This routines makes sure line n is read in. */
void most_read_to_line(int n)
{
int dn;
long nbytes;
if (Most_Buf->fd == -1) return;
n += 2 * SLtt_Screen_Rows;
dn = n - Most_Num_Lines;
if (dn < 0) return;
nbytes = 0;
if (Most_Num_Lines)
nbytes = dn * ((Most_Eob - Most_Beg) / Most_Num_Lines);
if (nbytes < 0x3FFF) nbytes = 0x3FFF;
while ((Most_Buf->fd != -1)
&& (n >= Most_Num_Lines)
&& (0 != most_read_file_dsc (nbytes / 0x3FFF, 1))
&& (SLKeyBoard_Quit == 0))
{
nbytes = 0;
if (Most_Num_Lines)
nbytes = dn * ((Most_Eob - Most_Beg) / Most_Num_Lines);
if (nbytes < 0x3FFF) nbytes = 0x3FFF;
}
}
int most_find_file(char *file)
{
Most_Buffer_Type *new_buf;
int n;
char msg[MAX_PATHLEN+20], *msgp;
int ret = 0;
new_buf = most_create_buffer(file);
(void) most_switch_to_buffer(new_buf);
First_Time_Hack = 1;
if (insert_file(file) < 0)
{
sprintf (msg, "%s failed to open.", file);
n = strlen (msg);
msgp = (char *) MOSTMALLOC((unsigned int) (n + 1));
strcpy (msgp, msg);
Most_Buf->beg = (unsigned char *) msgp;
Most_Buf->end = Most_Buf->beg + n;
Most_Buf->fd = -1;
Most_Num_Lines = 1;
ret = -1;
}
First_Time_Hack = 0;
Most_Beg = Most_Buf->beg;
Most_Eob = Most_Buf->end;
Most_C_Offset = 0;
Most_C_Line = 1;
Most_Column = 1;
return ret;
}
/* if the file is visible in a window, move to the window and return 1
else return 0 */
Most_Window_Type *most_file_visible(char *file)
{
Most_Window_Type *w;
w = Most_Win;
Most_Win = Most_Top_Win;
do
{
if (!strcmp(Most_Win->buf->file,file))
{
most_set_window(Most_Win);
return(Most_Win);
}
Most_Win = Most_Win->next;
}
while (Most_Win != Most_Top_Win);
Most_Win = w;
return(NULL);
}
void most_reread_file (void)
{
char file[MAX_PATHLEN];
int line = Most_C_Line;
if (-1 == access(Most_Buf->file, 0)) /* does it exist? */
{
most_message("File not found.",1);
return;
}
most_one_window ();
strcpy (file, Most_Buf->file);
most_free_window_buffer ();
(void) most_find_file (file);
most_goto_line (line);
most_window_buffer ();
}
static int find_file_in_window(char *file)
{
if (NULL != most_file_visible(file))
{
most_message ("File is already visible.", 1);
return -2;
}
if (-1 == access(file, 0)) /* does it exist? */
{
most_message("File not found.",1);
return -1;
}
most_free_window_buffer();
(void) most_find_file(file);
most_window_buffer();
most_redraw_window();
most_update_status();
return 0;
}
static void format_next_file (char *mbuf, int j, char *file)
{
int len, max_len;
len = strlen (file);
max_len = SLtt_Screen_Cols - 25;
if (len > max_len)
{
sprintf(mbuf, "Next File (%d): ...%s", j, file + (len - max_len));
}
else sprintf(mbuf, "Next File (%d): %s", j, file);
}
void most_do_next_file(int *j)
{
char mbuf[256], *curr_file;
unsigned char ch;
most_select_minibuffer();
if (*j >= Most_Num_Files) *j = 0;
curr_file = Most_File_Ring[*j];
while (1)
{
format_next_file (mbuf, *j, curr_file);
SLsmg_write_string (mbuf);
SLsmg_erase_eol ();
SLsmg_gotorc (SLtt_Screen_Rows - 1, 0);
SLsmg_refresh ();
ch = most_getkey();
#ifndef IBMPC_SYSTEM
if (ch != '\033') break;
if (ch = most_getkey(), (ch != 'O') && (ch != '[')) continue;
if (ch = most_getkey(), (ch != 'A') && (ch != 'B')) continue;
#else
if ((ch != 0) && (ch != 0xE0))
break;
ch = most_getkey ();
if (ch != 'H') ch = 'B'; else ch = 'A';
#endif
if (ch == 'B')
{
if (*j == 0) *j = Most_Num_Files;
(*j)--;
}
else /* ch == 'A' */
{
(*j)++;
if (*j == Most_Num_Files) *j = 0;
}
curr_file = Most_File_Ring[*j];
}
most_exit_minibuffer();
(*j)++;
if ((ch == 'Q') || (ch == 'q'))
{
most_exit_most ();
}
else find_file_in_window(curr_file);
}
/* extracts directory from file string, returns false if no dir */
int most_head(char *file, char *dir)
{
int n;
if (file == NULL) return 0;
(void) strcpy(dir,file);
n = strlen(file) - 1;
#ifdef VMS
while((n > -1) && (file[n] != ']') && (file[n] != ':')) n--;
#else
while((n > -1) && file[n] != '/') n--;
#endif
n++;
dir[n] = '\0';
return(n);
}
/* returns a pointer to the tail of file */
static int tail(char *filed, char **filep)
{
int n;
n = strlen(filed) - 1;
#ifdef VMS
while((n > -1) && ((filed[n] != ']') && (filed[n] != ':'))) n--;
#else
while((n > -1) && (filed[n] != '/')) n--;
#endif
n++;
*filep = (filed + n);
return(n);
}
/* assume path is big enough to hold new expanded version */
static int expand_path(char *path)
{
#ifndef VMS
int n;
#endif
/* really cheat here-- let system do it. The path must exist!! */
if (chdir(path))
{
most_message(path,1);
return(0);
}
else
{
most_get_cdir(path);
(void) chdir(Most_C_Dir);
#ifndef VMS
n = strlen(path);
if (path[n-1] == '/') return(1);
path[n++] = '/'; path[n] = 0;
#endif
}
return(1);
}
#if 0
static void most_cd (void)
{
char tmp_dir[MAX_PATHLEN];
int n;
if (Most_Secure_Mode)
{
most_message ("CD disabled in secure mode.", 1);
return;
}
strcpy(tmp_dir,Most_C_Dir);
if (most_read_from_minibuffer("cd ",Most_C_Dir) == -1) return;
if (!chdir(Most_C_Dir))
{
most_get_cdir(Most_C_Dir); /* expands ../ etc... */
n = strlen(Most_C_Dir);
# ifndef VMS
if (Most_C_Dir[n-1] == '/') return;
Most_C_Dir[n++] = '/'; Most_C_Dir[n] = 0;
# endif
return;
}
strcpy(Most_C_Dir,tmp_dir);
(void) chdir(Most_C_Dir);
most_message("Unable to change directory.",1);
}
#endif
void most_user_get_file()
{
char path[MAX_PATHLEN], file[MAX_PATHLEN], *name;
#ifdef VMS
unsigned int i, imax;
#endif
if (Most_Secure_Mode)
{
most_message ("Getting a file is not permitted in secure mode.", 1);
return;
}
if (!most_head(Most_Win->buf->file,file))
strcpy(file,Most_C_Dir);
if (most_read_from_minibuffer("Find File: ", file, file, sizeof(file)) == -1)
return;
if (most_head(file,path))
{
expand_path(path);
tail(file,&name);
strcat(path,name);
name = path;
}
else name = file;
#ifdef VMS
imax = strlen (name);
for (i = 0; i < imax; i++)
name [i] = toupper (name[i]);
#endif
if (find_file_in_window(name) < 0) return;
/*
** add to file ring if successful
*/
if ((NULL != most_file_visible(name))
&& (Most_Num_Files < MOST_MAX_FILES))
{
Most_File_Ring[Most_Num_Files] = (char*) MOSTMALLOC(strlen(name) + 1);
strcpy(Most_File_Ring[Most_Num_Files++],name);
}
}
void most_get_cdir(char *dir)
{
#ifdef sequent
getwd(dir);
#else
# ifdef HAVE_GETCWD
getcwd(dir, MAX_PATHLEN);
# else
getwd(dir);
# endif
#endif
#ifndef VMS
{
int i;
i = strlen(dir);
if (i && (dir[i - 1] != '/')) dir[i++] = '/';
dir[i] = 0;
}
#endif
}