⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 view.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
/* {{{ Copyright notice */

/* View file module for the Midnight Commander
   Copyright (C) 1994, 1995, 1996 The Free Software Foundation
   Written by: 1994, 1995, 1998 Miguel de Icaza
               1994, 1995 Janne Kukonlehto
               1995 Jakub Jelinek
               1996 Joseph M. Hinkle
	       1997 Norbert Warmuth

   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.  */

/* }}} */
/* {{{ Declarations */
#include <config.h>
#include "x.h"
#include <stdio.h>
#ifdef OS2_NT
#   include <io.h>
#endif
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
#include <string.h>
#include "tty.h"
#include <sys/stat.h>
#ifdef HAVE_MMAP
#   include <sys/mman.h>
#endif
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
#    include <unistd.h>
#endif
#include <ctype.h>	/* For toupper() */
#include <stdlib.h>	/* atoi() */
#include <malloc.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
#include "mem.h"
#include "mad.h"
#include "util.h"
#include "dlg.h"		/* Needed by widget.h */
#include "widget.h"		/* Needed for buttonbar_new */
#include "color.h"
#include "dialog.h"
#include "file.h"
#include "mouse.h"
#include "global.h"
#include "help.h"
#include "key.h"		/* For mi_getch() */
#include "layout.h"
#include "wtools.h"		/* For query_set_sel() */
#if defined(HAVE_RX_H) && defined(HAVE_REGCOMP)
#    include <rx.h>
#else
#    include "regex.h"
#endif
#include "fs.h"
#include "../vfs/vfs.h"
#include "dir.h"
#include "panel.h" /* Needed for current_panel and other_panel */
#include "win.h"
#include "main.h"		/* For the externs */
#define WANT_WIDGETS
#include "view.h"

#ifndef MAP_FILE
#define MAP_FILE 0
#endif

/* Block size for reading files in parts */
#define READ_BLOCK 8192
#define VIEW_PAGE_SIZE 8192

#ifdef IS_AIX
#   define IFAIX(x) case (x):
#else
#   define IFAIX(x)
#endif

/* Maxlimit for skipping updates */
int max_dirt_limit =
#ifdef OS2_NT
0;
#else
10;
#endif

/* Our callback */
static int view_callback (Dlg_head *h, WView *view, int msg, int par);

/* If set, show a ruler */
int ruler = 0;

/* Scrolling is done in pages or line increments */
int mouse_move_pages_viewer = 1;

/* Used to compute the bottom first variable */
int have_fast_cpu = 0;

/* wrap mode default */
int global_wrap_mode = 1;

int default_hex_mode = 0;
int default_hexedit_mode = 0;
int default_magic_flag = 1;
int default_nroff_flag = 1;
int altered_hex_mode = 0;
int altered_magic_flag = 0;
int altered_nroff_flag = 0;
/* }}} */

/* "$Id: view.c 15218 2005-05-11 16:50:39Z weiden $" */

static char hex_char[] = "0123456789ABCDEF";

/* }}} */
/* {{{ Clean-up functions */

void
close_view_file (WView *view)
{
    if (view->file != -1){
	mc_close (view->file);
	view->file = -1;
    }
}

void
free_file (WView *view)
{
    int i;

#ifdef HAVE_MMAP

    if (view->mmapping){
	mc_munmap (view->data, view->s.st_size);
	close_view_file (view);
    } else
#endif /* HAVE_MMAP */
    {
	if (view->reading_pipe){
	    /* Check error messages */
	    if (!view->have_frame)
		check_error_pipe ();

	    /* Close pipe */
	    pclose (view->stdfile);
	    view->stdfile = NULL;

	    /* Ignore errors because we don't want to hear about broken pipe */
	    close_error_pipe (-1, NULL);
	} else
	    close_view_file (view);
    }
    /* Block_ptr may be zero if the file was a file with 0 bytes */
    if (view->growing_buffer && view->block_ptr){
	for (i = 0; i < view->blocks; i++){
	    free (view->block_ptr [i].data);
	}
	free (view->block_ptr);
    }
}

/* Valid parameters for second parameter to set_monitor */
enum { off, on };

/* Both views */
void
view_done (WView *view)
{
	set_monitor (view, off);
#ifndef HAVE_MMAP
	/* alex: release core, used to replace mmap */
	if (!view->growing_buffer && view->data != NULL)
	{
		free(view->data);
		view->data = NULL;
	}
#endif /* HAVE_MMAP */

    if (view->view_active){
	if (view->localcopy)
	    mc_ungetlocalcopy (view->filename, view->localcopy, 0);
	free_file (view);
	free (view->filename);
	if (view->command)
	    free (view->command);
    }
    view->view_active = 0;
    default_hex_mode = view->hex_mode;
    default_nroff_flag = view->viewer_nroff_flag;
    default_magic_flag = view->viewer_magic_flag;
}

static void view_hook (void *);

void
view_destroy (WView *view)
{
    view_done (view);
    if (view->have_frame)
	delete_hook (&select_file_hook, view_hook);
    x_destroy_view (view);
}

static int
get_byte (WView *view, int byte_index)
{
    int page   = byte_index / VIEW_PAGE_SIZE + 1;
    int offset = byte_index % VIEW_PAGE_SIZE;
    int i, n;
    block_ptr_t *tmp;

    if (view->growing_buffer){
	if (page > view->blocks){
	    tmp = xmalloc (sizeof (block_ptr_t) * page, "get_byte");
	    if (view->block_ptr){
		bcopy (view->block_ptr, tmp, sizeof (block_ptr_t) *
		       view->blocks);
		free (view->block_ptr);
	    }
	    view->block_ptr = tmp;
	    for (i = view->blocks; i < page; i++){
		char *p = malloc (VIEW_PAGE_SIZE);
		view->block_ptr [i].data = p;
		if (!p)
		    return '\n';
		if (view->stdfile != NULL)
		    n = fread (p, 1, VIEW_PAGE_SIZE, view->stdfile);
		else
		    n = mc_read (view->file, p, VIEW_PAGE_SIZE);
		if (n != -1)
		    view->bytes_read += n;
		if (view->s.st_size < view->bytes_read){
		    view->bottom_first = -1; /* Invalidate cache */
		    view->s.st_size = view->bytes_read;
		    view->last_byte = view->bytes_read;
		    if (view->reading_pipe)
			view->last_byte = view->first + view->bytes_read;
		}
		/* To force loading the next page */
		if (n == VIEW_PAGE_SIZE && view->reading_pipe){
		    view->last_byte++;
		}
	    }
	    view->blocks = page;
	}
	if (byte_index > view->bytes_read){
	    return -1;
	} else
	    return view->block_ptr [page-1].data [offset];
    } else {
    	if (byte_index >= view->last_byte)
    	    return -1;
    	else
	    return view->data [byte_index];
    }
}

static void
enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node)
{
    struct hexedit_change_node *curr = *head;

    while (curr) {
        if (node->offset < curr->offset) {
            *head = node;
            node->next = curr;
            return;
        }
        head = (struct hexedit_change_node **) curr;
        curr = curr->next;
    }
    *head = node;
    node->next = curr;
}

static void move_right (WView *);

static void
put_editkey (WView *view, unsigned char key)
{
    struct hexedit_change_node *node;
    unsigned char byte_val;

    if (!view->hexedit_mode || view->growing_buffer != 0)
        return;

    /* Has there been a change at this position ? */
    node = view->change_list;
    while (node) {
        if (node->offset != view->edit_cursor)
            node = node->next;
        else
            break;
    }

    if (view->view_side == view_side_left) {
        /* Hex editing */

        if (key >= '0' && key <= '9')
            key -= '0';
        else if (key >= 'A' && key <= 'F')
            key -= '7';
        else if (key >= 'a' && key <= 'f')
            key -= 'W';
        else
            return;

        if (node)
            byte_val = node->value;
        else
            byte_val = get_byte(view, view->edit_cursor);

        if (view->nib_shift == 0) {
            byte_val = (byte_val & 0x0f) | (key << 4);
        } else {
            byte_val = (byte_val & 0xf0) | (key);
        }
    } else {
        /* Text editing */
        byte_val = key;
    }
    if (!node) {
        node = (struct hexedit_change_node *)
                    xmalloc(sizeof(struct hexedit_change_node), "HexEdit");

        if (node) {
#ifndef HAVE_MMAP
			/*
			**	alex@bcs.zaporizhzhe.ua: here we are using file copy
			**	completely loaded into memory, so we can replace bytes
			**	in view->data array to allow changes to be reflected
			**	when user switches back to ascii mode
			*/
			view->data[view->edit_cursor] = byte_val;
#endif /* HAVE_MMAP */
            node->offset = view->edit_cursor;
            node->value = byte_val;
            enqueue_change (&view->change_list, node);
        }
    } else {
        node->value = byte_val;
    }
    view->dirty++;
    view_update (view);
    move_right (view);
}

static void
free_change_list (WView *view)
{
    struct hexedit_change_node *n = view->change_list;

    while (n) {
        view->change_list = n->next;
        free (n);
        n = view->change_list;
    }
    view->file_dirty = 0;
    view->dirty++;
}

static void
save_edit_changes (WView *view)
{
    struct hexedit_change_node *node = view->change_list;
    int fp;

    fp = open (view->filename, O_WRONLY);
    if (fp >= 0) {
        while (node) {
            lseek (fp, node->offset, SEEK_SET);
            write (fp, &node->value, 1);
            node = node->next;
        }
        close (fp);
    }
    free_change_list (view);
}

static int
view_ok_to_quit (WView *view)
{
    int r;
    char *text;

    if (!view->change_list)
	return 1;

    query_set_sel (1);
    text = copy_strings (_("File: \n\n    "), view->filename,
			 _("\n\nhas been modified, do you want to save the changes?\n"), NULL);

    r = query_dialog (_(" Save changes "), text, 2, 3, _("&Yes"), _("&No"), _("&Cancel"));
    free (text);

    switch (r) {
    case 0:
	save_edit_changes (view);
	return 1;
    case 1:
	free_change_list (view);
	return 1;
    default:
	return 0;
    }
}

static char *
set_view_init_error (WView *view, char *msg)
{
    view->growing_buffer = 0;
    view->reading_pipe   = 0;
    view->first = 0;
    view->last_byte = 0;
    if (msg){
	view->bytes_read = strlen (msg);
	return strdup (msg);
    }
    return 0;
}

/* return values: 0 for success, else points to error message */
static char *
init_growing_view (WView *view, char *name, char *filename)
{
    view->growing_buffer = 1;

    if (name){
	view->reading_pipe = 1;
	view->s.st_size = 0;

	open_error_pipe ();
	if ((view->stdfile = popen (name, "r")) == NULL){
	    close_error_pipe (view->have_frame?-1:1, view->data);
	    return set_view_init_error (view, _(" Can't spawn child program "));
	}

#ifndef HAVE_XVIEW
	/* First, check if filter produced any output */
	get_byte (view, 0);
	if (view->bytes_read <= 0){
	    pclose (view->stdfile);
	    view->stdfile = NULL;
	    close_error_pipe (view->have_frame?-1:1, view->data);
	    return set_view_init_error (view, _(" Empty output from child filter "));
	}
#endif
    } else {
        view->stdfile = NULL;
	if ((view->file = mc_open (filename, O_RDONLY)) == -1)
	    return set_view_init_error (view, _(" Could not open file "));
    }
    return 0;
}

/* Load filename into core */
/* returns:
   -1 on failure.
   if (have_frame), we return success, but data points to a
   error message instead of the file buffer (quick_view feature).
*/
static char *load_view_file (WView *view, char *filename)
{
    char *cmd;
    int  type;

    if ((view->file = mc_open (filename, O_RDONLY)) < 0){
	set_view_init_error (view, 0);
	return (copy_strings (_(" Can't open file \""),
			      filename, "\"\n ",
			      unix_error_string (errno), " ", 0));

    }
    if (mc_fstat (view->file, &view->s) < 0){
	set_view_init_error (view, 0);
	close_view_file (view);
	return copy_strings (_(" Can't stat file \n "),
			     unix_error_string (errno), " ", 0);
    }
    if (S_ISDIR (view->s.st_mode) || S_ISSOCK (view->s.st_mode)
	|| S_ISFIFO (view->s.st_mode)){
	close_view_file (view);
	return set_view_init_error (view, _(" Can't view: not a regular file "));
    }

    if (view->s.st_size == 0){
	/* Must be one of those nice files that grow (/proc) */
	close_view_file (view);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -