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

📄 edit.c

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

   Copyright (C) 1996, 1997 the Free Software Foundation

   Authors: 1996, 1997 Paul Sheer

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

#define _EDIT_C THIS_IS

#include <config.h>
#if defined(OS2_NT)
#    include <io.h>
#    include <fcntl.h>
#    define CR_LF_TRANSLATION
#endif
#include "edit.h"

#ifdef SCO_FLAVOR
#	include <sys/timeb.h>
#endif /* SCO_FLAVOR */
#include <time.h>	/* for ctime() */

/*
 *
 * here's a quick sketch of the layout: (don't run this through indent.)
 *
 * (b1 is buffers1 and b2 is buffers2)
 *
 *                                       |
 * \0\0\0\0\0m e _ f i l e . \nf i n . \n|T h i s _ i s _ s o\0\0\0\0\0\0\0\0\0
 * ______________________________________|______________________________________
 *                                       |
 * ...  |  b2[2]   |  b2[1]   |  b2[0]   |  b1[0]   |  b1[1]   |  b1[2]   | ...
 *      |->        |->        |->        |->        |->        |->        |
 *                                       |
 *           _<------------------------->|<----------------->_
 *                   WEdit->curs2        |   WEdit->curs1
 *           ^                           |                   ^
 *           |                          ^|^                  |
 *         cursor                       |||                cursor
 *                                      |||
 *                              file end|||file beginning
 *                                       |
 *                                       |
 *
 *           _
 * This_is_some_file
 * fin.
 *
 *
 */

/*
   returns a byte from any location in the file.
   Returns '\n' if out of bounds.
 */
int edit_get_byte (WEdit * edit, long byte_index)
{
    unsigned long p;
    if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
	return '\n';

    if (byte_index >= edit->curs1) {
	p = edit->curs1 + edit->curs2 - byte_index - 1;
	return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
    } else {
	return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
    }
}

char *edit_get_buffer_as_text (WEdit * e)
{
    int l, i;
    char *t;
    l = e->curs1 + e->curs2;
    t = CMalloc (l + 1);
    for (i = 0; i < l; i++)
	t[i] = edit_get_byte (e, i);
    t[l] = 0;
    return t;
}

/* Initialisation routines */

/* returns 1 on error */
/* loads file OR text into buffers. Only one must be none-NULL. */
/* cursor set to start of file */
int init_dynamic_edit_buffers (WEdit * edit, const char *filename, const char *text)
{

#if defined CR_LF_TRANSLATION
    /* Variables needed for safe handling of Translation from Microsoft CR/LF EOL to
       Unix Style LF EOL - Franco */
    long bytes_wanted,bytes_read,bytes_missing;
    char *p;
#endif

    long buf;
    int j, file = 0, buf2;

    for (j = 0; j <= MAXBUFF; j++) {
	edit->buffers1[j] = NULL;
	edit->buffers2[j] = NULL;
    }

    if (filename)
	if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT)) == -1) {
/* The file-name is printed after the ':' */
	    edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename, " ", 0)));
	    return 1;
	}
    edit->curs2 = edit->last_byte;

    buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;

    edit->buffers2[buf2] = CMalloc (EDIT_BUF_SIZE);

/*
_read returns the number of bytes read,
which may be less than count if there are fewer than count bytes left in the file
or if the file was opened in text mode,
in which case each carriage return杔inefeed (CR-LF) pair is replaced
with a single linefeed character. Only the single linefeed character is counted
in the return value. The replacement does not affect the file pointer.

_eof returns 1 if the current position is end of file, or 0 if it is not.
A return value of -1 indicates an error; in this case, errno is set to EBADF,
which indicates an invalid file handle.
*/
    if (filename){

#if defined CR_LF_TRANSLATION
	bytes_wanted=edit->curs2 & M_EDIT_BUF_SIZE;
	p = (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
	bytes_read = read (file, p , edit->curs2 & M_EDIT_BUF_SIZE);
	bytes_missing = bytes_wanted - bytes_read ;
	while(bytes_missing ){
		p += bytes_read;
		bytes_read = read(file,p,bytes_missing);
		if(bytes_read <= 0) break;
		bytes_missing -= bytes_read ;
	}
#else
	read (file, (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE);
#endif
    }
    else {
	memcpy (edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), text, edit->curs2 & M_EDIT_BUF_SIZE);
	text += edit->curs2 & M_EDIT_BUF_SIZE;
    }

    for (buf = buf2 - 1; buf >= 0; buf--) {
	edit->buffers2[buf] = CMalloc (EDIT_BUF_SIZE);
 	if (filename){
#if defined CR_LF_TRANSLATION
		bytes_wanted = EDIT_BUF_SIZE;
		p = (char *) edit->buffers2[buf];
		bytes_read = read (file, p, EDIT_BUF_SIZE);
		bytes_missing = bytes_wanted - bytes_read ;
		while(bytes_missing ){
			p += bytes_read;
			bytes_read = read(file,p,bytes_missing);
			if(bytes_read <= 0) break;
			bytes_missing -= bytes_read ;
		}
#else
	    read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
#endif
 	}
	else {
	    memcpy (edit->buffers2[buf], text, EDIT_BUF_SIZE);
	    text += EDIT_BUF_SIZE;
	}
    }

    edit->curs1 = 0;
    if (filename)
	close (file);

    return 0;
}

/* returns 1 on error */
int edit_load_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size)
{
    struct stat s;
    int file;

/* VARS for Lastbyte calculation in TEXT mode FRANCO */
#if defined CR_LF_TRANSLATION
 char tmp_buf[1024];
 long real_size,bytes_read;
#endif

    if (text) {
	edit->last_byte = text_size;
	filename = NULL;
    } else {
#if defined(MIDNIGHT) || defined(GTK)
    if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0)
	{
		close(creat((char *) filename, 0666));
		if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0) {
			edit_error_dialog (_(" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename, ", for reading ", 0)));
			return 1;
		}
		edit->delete_file = 1;
	}
#else
	if ((file = open ((char *) filename, O_RDONLY)) < 0) {
	    edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename, " ", 0)));
	    return 1;
	}
#endif
	if (stat ((char *) filename, &s) < 0) {
	    close (file);
/* The file-name is printed after the ':' */
	    edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Cannot get size/permissions info on file: "), filename, " ", 0)));
	    return 1;
	}
	if (S_ISDIR (s.st_mode) || S_ISSOCK (s.st_mode)
	    || S_ISFIFO (s.st_mode)) {
	    close (file);
/* The file-name is printed after the ':' */
	    edit_error_dialog (_(" Error "), catstrs (_(" Not an ordinary file: "), filename, " ", 0));
	    return 1;
	}
	if (s.st_size >= SIZE_LIMIT) {
	    close (file);
/* The file-name is printed after the ':' */
	    edit_error_dialog (_(" Error "), catstrs (_(" File is too large: "), \
		filename, _(" \n Increase edit.h:MAXBUF and recompile the editor. "), 0));
	    return 1;
	}

/* Lastbyte calculation in TEXT mode FRANCO */
#if defined CR_LF_TRANSLATION
	if(file && (!text)){
		real_size=0;
		tmp_buf[1024]=0;
		while((bytes_read = read(file,tmp_buf,1024)) > 0){
			real_size += bytes_read;
		}
		s.st_size = real_size;
	}

#endif

	close (file);
	edit->last_byte = s.st_size;
	edit->stat = s;
    }

    return init_dynamic_edit_buffers (edit, filename, text);
}

#ifdef MIDNIGHT
#define space_width 1
#else
int space_width;
extern int option_long_whitespace;
extern unsigned char per_char[256];

void edit_set_space_width (int s)
{
    space_width = s;
}

#endif

/* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this function to do an malloc for you */
WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size)
{
    char *f;
#ifndef MIDNIGHT
    if (option_long_whitespace)
	edit_set_space_width (per_char[' '] * 2);
    else
	edit_set_space_width (per_char[' ']);
#endif
    if (!edit)
	edit = malloc (sizeof (WEdit));
    if (!edit) {
	edit_error_dialog (_(" Error "), _(" Error allocating memory "));
	return 0;
    }
    memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
#ifndef MIDNIGHT
    edit->max_column = columns * FONT_MEAN_WIDTH;
#endif
    edit->num_widget_lines = lines;
    edit->num_widget_columns = columns;
    edit->stat.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
    edit->stat.st_uid = getuid ();
    edit->stat.st_gid = getgid ();
    edit->bracket = -1;
    if (!dir)
	dir = "";
    f = (char *) filename;
    if (filename)
	f = catstrs (dir, filename, 0);
    if (edit_load_file (edit, f, text, text_size)) {
/* edit_load_file already gives an error message */
	free (edit);
	return 0;
    }
    edit->force |= REDRAW_PAGE;
    if (filename) {
	filename = catstrs (dir, filename, 0);
	edit_split_filename (edit, (char *) filename);
    } else {
	edit->filename = strdup ("");
	edit->dir = strdup(dir);
    }
    edit->stack_size = START_STACK_SIZE;
    edit->stack_size_mask = START_STACK_SIZE - 1;
    edit->undo_stack = malloc ((edit->stack_size + 10) * sizeof (long));
    if (!edit->undo_stack) {
	edit_error_dialog (_(" Error "), _(" Error allocating memory "));
	free (edit);
	return 0;
    }
    edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
    edit_load_syntax (edit, 0, 0);
    {
	int fg, bg;
	edit_get_syntax_color (edit, -1, &fg, &bg);
    }
    return edit;
}


/* clear the edit struct, freeing everything in it. returns 1 on success */
int edit_clean (WEdit * edit)
{
    if (edit) {
	int j = 0;
	edit_free_syntax_rules (edit);
	for (; j <= MAXBUFF; j++) {
	    if (edit->buffers1[j] != NULL)
		free (edit->buffers1[j]);
	    if (edit->buffers2[j] != NULL)
		free (edit->buffers2[j]);
	}

	if (edit->undo_stack)
	    free (edit->undo_stack);
	if (edit->filename)
	    free (edit->filename);
	if (edit->dir)
	    free (edit->dir);
/* we don't want to clear the widget */
	memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
	return 1;
    }
    return 0;
}


/* returns 1 on success */
int edit_renew (WEdit * edit)
{
    int lines = edit->num_widget_lines;
    int columns = edit->num_widget_columns;
    char *dir;

    if (edit->dir)
	dir = strdup (edit->dir);
    else
	dir = 0;

    edit_clean (edit);
    if (!edit_init (edit, lines, columns, 0, "", dir, 0))
	return 0;
    return 1;
}

/* returns 1 on success */
int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size)
{
    int lines = edit->num_widget_lines;
    int columns = edit->num_widget_columns;
    edit_clean (edit);
    if (!edit_init (edit, lines, columns, filename, text, dir, text_size)) {
	return 0;
    }
    return 1;
}


/*
   Recording stack for undo:
   The following is an implementation of a compressed stack. Identical
   pushes are recorded by a negative prefix indicating the number of times the
   same char was pushed. This saves space for repeated curs-left or curs-right
   delete etc.

   eg:

  pushed:       stored:

   a
   b             a
   b            -3
   b             b
   c  -->       -4
   c             c
   c             d
   c
   d

   If the stack long int is 0-255 it represents a normal insert (from a backspace),
   256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
   of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
   set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
   position.

   The only way the curser moves or the buffer is changed is through the routines:
   insert, backspace, insert_ahead, delete, and cursor_move.
   These record the reverse undo movements onto the stack each time they are
   called.

   Each key press results in a set of actions (insert; delete ...). So each time
   a key is pressed the current position of start_display is pushed as
   KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
   over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
   tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)

*/

static int push_action_disabled = 0;

void edit_push_action (WEdit * edit, long c,...)
{
    unsigned long sp = edit->stack_pointer;
    unsigned long spm1;
    long *t;
/* first enlarge the stack if necessary */
    if (sp > edit->stack_size - 10) {	/* say */
	if (option_max_undo < 256)
	    option_max_undo = 256;
	if (edit->stack_size < option_max_undo) {
	    t = malloc ((edit->stack_size * 2 + 10) * sizeof (long));

⌨️ 快捷键说明

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