📄 edit.c
字号:
/* editor low level data handling and cursor fundamentals. Copyright (C) 1996-2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.*/#define _EDIT_C THIS_IS#include <config.h>#if defined(NEEDS_IO_H)# 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() */#if defined (HAVE_MAD) && ! defined (MIDNIGHT) && ! defined (GTK)#include "mad.h"#endif/* * * 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. */static int push_action_disabled = 0;#ifdef NO_INLINE_GETBYTEint 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]; }}#endifchar *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;}/* Note on CRLF->LF translation: */#if MY_O_TEXT#error MY_O_TEXT is depreciated. CR_LF_TRANSLATION must be defined which does CR-LF translation internally. See note in source.#endif/* The edit_open_file (previously edit_load_file) function uses init_dynamic_edit_buffers to load a file. This is unnecessary since you can just as well fopen the file and insert the characters one by one. The real reason for init_dynamic_edit_buffers (besides allocating the buffers) is as an optimisation - it uses raw block reads and inserts large chunks at a time. It is hence extremely fast at loading files. Where we might not want to use it is if we were doing CRLF->LF translation or if we were reading from a pipe. *//* Initialisation routines *//* returns 1 on error *//* loads file OR text into buffers. Only one must be none-NULL. *//* cursor set to start of file *//* FIXME: implement proper error handling on failed reads */int init_dynamic_edit_buffers (WEdit * edit, const char *filename, const char *text){ long buf; int j, file = -1, buf2; for (j = 0; j <= MAXBUFF; j++) { edit->buffers1[j] = NULL; edit->buffers2[j] = NULL; } if (filename) if ((file = open ((char *) filename, O_RDONLY)) == -1) {/* The file-name is printed after the ':' */ edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed 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); if (filename) { readall (file, (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE); } 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) { readall (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE); } else { memcpy (edit->buffers2[buf], text, EDIT_BUF_SIZE); text += EDIT_BUF_SIZE; } } edit->curs1 = 0; if (file != -1) close (file); return 0;}/* detecting an error on save is easy: just check if every byte has been written. *//* detecting an error on read, is not so easy 'cos there is not way to tell whether you read everything or not. *//* FIXME: add proper `triple_pipe_open' to read, write and check errors. */static struct edit_filters { char *read, *write, *extension;} all_filters[] = { { "bzip2 -cd %s", "bzip2 > %s", ".bz2" }, { "gzip -cd %s", "gzip > %s", ".gz" }, { "compress -cd %s", "compress > %s", ".Z" }};static int edit_find_filter (const char *filename){ int i, l; if (!filename) return -1; l = strlen (filename); for (i = 0; i < sizeof (all_filters) / sizeof (struct edit_filters); i++) { int e; e = strlen (all_filters[i].extension); if (l > e) if (!strcmp (all_filters[i].extension, filename + l - e)) return i; } return -1;}char *edit_get_filter (const char *filename){ int i, l; char *p; i = edit_find_filter (filename); if (i < 0) return 0; l = strlen (filename); p = malloc (strlen (all_filters[i].read) + l + 2); sprintf (p, all_filters[i].read, filename); return p;}char *edit_get_write_filter (char *writename, char *filename){ int i, l; char *p; i = edit_find_filter (filename); if (i < 0) return 0; l = strlen (writename); p = malloc (strlen (all_filters[i].write) + l + 2); sprintf (p, all_filters[i].write, writename); return p;}#ifdef CR_LF_TRANSLATION/* reads into buffer, replace \r\n with \n */long edit_insert_stream (WEdit * edit, FILE * f){ int a = -1, b; long i; while ((b = fgetc (f)) >= 0) { if (a == '\r' && b == '\n') { edit_insert (edit, '\n'); i++; a = -1; continue; } else if (a >= 0) { edit_insert (edit, a); i++; } a = b; } if (a >= 0) edit_insert (edit, a); return i;}/* writes buffer, replaces, replace \n with \r\n */long edit_write_stream (WEdit * edit, FILE * f){ long i; int c; for (i = 0; i < edit->last_byte; i++) { c = edit_get_byte (edit, i); if (c == '\n') { if (fputc ('\r', f) < 0) break; if (fputc ('\n', f) < 0) break; } else { if (fputc (c, f) < 0) break; } } return i;}#elselong edit_insert_stream (WEdit * edit, int fd){ int len; long total = 0; for (;;) { char *p, *q; len = 8192; q = p = read_pipe (fd, &len); if (!len) { free (p); return total; } total += len; while (len--) edit_insert (edit, *p++); free (q); } return total;}long edit_write_stream (WEdit * edit, FILE * f){ long i; for (i = 0; i < edit->last_byte; i++) { int r; while ((r = fputc (edit_get_byte (edit, i), f)) == -1 && errno == EINTR); if (r < 0) break; } return i;}#endif#define TEMP_BUF_LEN 1024/* inserts a file at the cursor, returns 1 on success */int edit_insert_file (WEdit * edit, const char *filename){ char *p; if ((p = edit_get_filter (filename))) { long current = edit->curs1; int f, g; char *a[8]; a[0] = "/bin/sh"; a[1] = "-c"; a[2] = p; a[3] = 0; if (triple_pipe_open (0, &f, &g, 0, "sh", a) > 0) { edit_insert_stream (edit, f); edit_cursor_move (edit, current - edit->curs1); free (p); p = read_pipe (g, 0); if (strlen (p)) { edit_error_dialog (_ (" Error "), catstrs (_ (" Error reading from pipe: "), p, " ", 0)); free (p); close (f); close (g); return 0; } close (f); close (g); } else { edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open pipe for reading: "), p, " ", 0))); free (p); return 0; } free (p);#ifdef CR_LF_TRANSLATION } else { FILE *f; long current = edit->curs1; f = fopen (filename, "r"); if (f) { edit_insert_stream (edit, f); edit_cursor_move (edit, current - edit->curs1); if (fclose (f)) { edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Error reading file: "), filename, " ", 0))); return 0; } } else { edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open file for reading: "), filename, " ", 0))); return 0; }#else } else { int i, file, blocklen; long current = edit->curs1; unsigned char *buf; if ((file = open ((char *) filename, O_RDONLY)) == -1) return 0; buf = malloc (TEMP_BUF_LEN); while ((blocklen = read (file, (char *) buf, TEMP_BUF_LEN)) > 0) { for (i = 0; i < blocklen; i++) edit_insert (edit, buf[i]); } edit_cursor_move (edit, current - edit->curs1); free (buf); close (file); if (blocklen) return 0;#endif } return 1;}static int check_file_access (WEdit *edit, const char *filename, struct stat *st){ int file;#if defined(MIDNIGHT) || defined(GTK) if ((file = open ((char *) filename, O_RDONLY)) < 0) { close (creat ((char *) filename, 0666)); if ((file = open ((char *) filename, O_RDONLY)) < 0) { edit_error_dialog (_ (" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename, ", for reading ", 0))); return 2; } }#else if ((file = open ((char *) filename, O_RDONLY)) < 0) { edit_error_dialog (_ (" Error "), get_sys_error (catstrs (_ (" Failed trying to open file for reading: "), filename, " ", 0))); return 1; }#endif if (stat ((char *) filename, st) < 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 (st->st_mode) || S_ISSOCK (st->st_mode) || S_ISFIFO (st->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 (st->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; } close (file); return 0;}/* returns 1 on error */int edit_open_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size){ struct stat st; if (text) { edit->last_byte = text_size; filename = 0; } else { int r; r = check_file_access (edit, filename, &st);#if defined(MIDNIGHT) || defined(GTK) if (r == 2) return edit->delete_file = 1;#endif if (r) return 1; edit->stat = st;#ifndef CR_LF_TRANSLATION edit->last_byte = st.st_size;#else/* going to read the file into the buffer later byte by byte */ edit->last_byte = 0; filename = 0; text = "";#endif } return init_dynamic_edit_buffers (edit, filename, text);}#ifdef MIDNIGHT#define space_width 1#elseint space_width;extern int option_long_whitespace;void edit_set_space_width (int s){ space_width = s;}#endifint (*edit_file_is_open) (char *) = 0;/* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this */WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size){ char *f; int to_free = 0; int use_filter = 0;#ifndef MIDNIGHT if (option_long_whitespace) edit_set_space_width (FONT_PER_CHAR(' ') * 2); else edit_set_space_width (FONT_PER_CHAR(' '));#endif if (!edit) { edit = malloc (sizeof (WEdit)); memset (edit, 0, sizeof (WEdit)); to_free = 1; } 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -