aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ring.cpp')
-rw-r--r--src/ring.cpp367
1 files changed, 25 insertions, 342 deletions
diff --git a/src/ring.cpp b/src/ring.cpp
index fdd8206..e7f7d75 100644
--- a/src/ring.cpp
+++ b/src/ring.cpp
@@ -19,21 +19,16 @@
#include "config.h"
#endif
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
#include <bsd/sys/queue.h>
#include <glib.h>
#include <glib/gprintf.h>
-#include <glib/gstdio.h>
#include <Scintilla.h>
#include "sciteco.h"
#include "interface.h"
+#include "ioview.h"
#include "undo.h"
#include "parser.h"
#include "expressions.h"
@@ -42,14 +37,6 @@
#include "error.h"
#include "ring.h"
-#ifdef HAVE_WINDOWS_H
-/* here it shouldn't cause conflicts with other headers */
-#include <windows.h>
-
-/* still need to clean up */
-#undef interface
-#endif
-
namespace SciTECO {
namespace States {
@@ -57,44 +44,6 @@ namespace States {
StateSaveFile savefile;
}
-#ifdef G_OS_WIN32
-
-typedef DWORD FileAttributes;
-/* INVALID_FILE_ATTRIBUTES already defined */
-
-static inline FileAttributes
-get_file_attributes(const gchar *filename)
-{
- return GetFileAttributes((LPCTSTR)filename);
-}
-
-static inline void
-set_file_attributes(const gchar *filename, FileAttributes attrs)
-{
- SetFileAttributes((LPCTSTR)filename, attrs);
-}
-
-#else
-
-typedef int FileAttributes;
-#define INVALID_FILE_ATTRIBUTES (-1)
-
-static inline FileAttributes
-get_file_attributes(const gchar *filename)
-{
- struct stat buf;
-
- return g_stat(filename, &buf) ? INVALID_FILE_ATTRIBUTES : buf.st_mode;
-}
-
-static inline void
-set_file_attributes(const gchar *filename, FileAttributes attrs)
-{
- g_chmod(filename, attrs);
-}
-
-#endif /* !G_OS_WIN32 */
-
void
Buffer::UndoTokenClose::run(void)
{
@@ -103,57 +52,30 @@ Buffer::UndoTokenClose::run(void)
delete buffer;
}
-/*
- * The following simple implementation of file reading is actually the
- * most efficient and useful in the common case of editing small files,
- * since
- * a) it works with minimal number of syscalls and
- * b) small files cause little temporary memory overhead.
- * Reading large files however could be very inefficient since the file
- * must first be read into memory and then copied in-memory. Also it could
- * result in thrashing.
- * Alternatively we could iteratively read into a smaller buffer trading
- * in speed against (temporary) memory consumption.
- * The best way to do it could be memory mapping the file as we could
- * let Scintilla copy from the file's virtual memory directly.
- * Unfortunately since every page of the mapped file is
- * only touched once by Scintilla TLB caching is useless and the TLB is
- * effectively thrashed with entries of the mapped file.
- * This results in the doubling of page faults and weighs out the other
- * advantages of memory mapping (has been benchmarked).
- *
- * So in the future, the following approach could be implemented:
- * 1.) On Unix/Posix, mmap() one page at a time, hopefully preventing
- * TLB thrashing.
- * 2.) On other platforms read into and copy from a statically sized buffer
- * (perhaps page-sized)
- */
void
-Buffer::load(const gchar *filename)
+Buffer::save(const gchar *filename)
{
- gchar *contents;
- gsize size;
-
- GError *gerror = NULL;
+ if (!filename && !Buffer::filename)
+ throw Error("File name expected");
- if (!g_file_get_contents(filename, &contents, &size, &gerror))
- throw GlibError(gerror);
+ IOView::save(filename ? : Buffer::filename);
- ssm(SCI_BEGINUNDOACTION);
- ssm(SCI_CLEARALL);
- ssm(SCI_APPENDTEXT, size, (sptr_t)contents);
- ssm(SCI_ENDUNDOACTION);
-
- g_free(contents);
-
- /* NOTE: currently buffer cannot be dirty */
-#if 0
+ /*
+ * Undirtify
+ * NOTE: info update is performed by set_filename()
+ */
interface.undo_info_update(this);
- undo.push_var(dirty);
- dirty = false;
-#endif
+ undo.push_var(dirty) = false;
- set_filename(filename);
+ /*
+ * FIXME: necessary also if the filename was not specified but the file
+ * is (was) new, in order to canonicalize the filename.
+ * May be circumvented by cananonicalizing without requiring the file
+ * name to exist (like readlink -f)
+ * NOTE: undo_info_update is already called above
+ */
+ undo.push_str(Buffer::filename);
+ set_filename(filename ? : Buffer::filename);
}
void
@@ -296,192 +218,6 @@ Ring::edit(const gchar *filename)
}
}
-#if 0
-
-/*
- * TODO: on UNIX it may be better to open() the current file, unlink() it
- * and keep the file descriptor in the UndoToken.
- * When the operation is undone, the file descriptor's contents are written to
- * the file (which should be efficient enough because it is written to the same
- * filesystem). This way we could avoid messing around with save point files.
- */
-
-#else
-
-class UndoTokenRestoreSavePoint : public UndoToken {
- gchar *savepoint;
- Buffer *buffer;
-
-public:
-#ifdef G_OS_WIN32
- FileAttributes orig_attrs;
-#endif
-
- UndoTokenRestoreSavePoint(gchar *_savepoint, Buffer *_buffer)
- : savepoint(_savepoint), buffer(_buffer) {}
- ~UndoTokenRestoreSavePoint()
- {
- if (savepoint)
- g_unlink(savepoint);
- g_free(savepoint);
- buffer->savepoint_id--;
- }
-
- void
- run(void)
- {
- if (!g_rename(savepoint, buffer->filename)) {
- g_free(savepoint);
- savepoint = NULL;
-#ifdef G_OS_WIN32
- if (orig_attrs != INVALID_FILE_ATTRIBUTES)
- set_file_attributes(buffer->filename,
- orig_attrs);
-#endif
- } else {
- interface.msg(InterfaceCurrent::MSG_WARNING,
- "Unable to restore save point file \"%s\"",
- savepoint);
- }
- }
-};
-
-static inline FileAttributes
-make_savepoint(Buffer *buffer)
-{
- gchar *dirname, *basename, *savepoint;
- gchar savepoint_basename[FILENAME_MAX];
-
- FileAttributes attributes = get_file_attributes(buffer->filename);
-
- basename = g_path_get_basename(buffer->filename);
- g_snprintf(savepoint_basename, sizeof(savepoint_basename),
- ".teco-%s-%d", basename, buffer->savepoint_id);
- g_free(basename);
- dirname = g_path_get_dirname(buffer->filename);
- savepoint = g_build_filename(dirname, savepoint_basename, NIL);
- g_free(dirname);
-
- if (!g_rename(buffer->filename, savepoint)) {
- UndoTokenRestoreSavePoint *token;
-
- buffer->savepoint_id++;
- token = new UndoTokenRestoreSavePoint(savepoint, buffer);
-#ifdef G_OS_WIN32
- token->orig_attrs = attributes;
- if (attributes != INVALID_FILE_ATTRIBUTES)
- set_file_attributes(savepoint,
- attributes | FILE_ATTRIBUTE_HIDDEN);
-#endif
- undo.push(token);
- } else {
- interface.msg(InterfaceCurrent::MSG_WARNING,
- "Unable to create save point file \"%s\"",
- savepoint);
- g_free(savepoint);
- }
-
- return attributes;
-}
-
-#endif /* !G_OS_UNIX */
-
-bool
-Ring::save(const gchar *filename)
-{
- const void *buffer;
- sptr_t gap;
- size_t size;
- FILE *file;
-
-#ifdef G_OS_UNIX
- struct stat file_stat;
- file_stat.st_uid = -1;
- file_stat.st_gid = -1;
-#endif
- FileAttributes attributes = INVALID_FILE_ATTRIBUTES;
-
- if (!current)
- return false;
-
- if (!filename && !current->filename)
- return false;
-
- /*
- * Undirtify
- * NOTE: info update is performed by current->set_filename()
- */
- interface.undo_info_update(current);
- undo.push_var(current->dirty) = false;
-
- /*
- * FIXME: necessary also if the filename was not specified but the file
- * is (was) new, in order to canonicalize the filename.
- * May be circumvented by cananonicalizing without requiring the file
- * name to exist (like readlink -f)
- * NOTE: undo_info_update is already called above
- */
- undo.push_str(current->filename);
- current->set_filename(filename ? : current->filename);
-
- if (undo.enabled) {
- if (g_file_test(current->filename, G_FILE_TEST_IS_REGULAR)) {
-#ifdef G_OS_UNIX
- g_stat(current->filename, &file_stat);
-#endif
- attributes = make_savepoint(current);
- } else {
- undo.push(new UndoTokenRemoveFile(current->filename));
- }
- }
-
- /* leaves mode intact if file exists */
- file = g_fopen(current->filename, "w");
- if (!file)
- return false;
-
- /* write part of buffer before gap */
- gap = interface.ssm(SCI_GETGAPPOSITION);
- if (gap > 0) {
- buffer = (const void *)interface.ssm(SCI_GETRANGEPOINTER,
- 0, gap);
- if (!fwrite(buffer, (size_t)gap, 1, file)) {
- fclose(file);
- return false;
- }
- }
-
- /* write part of buffer after gap */
- size = interface.ssm(SCI_GETLENGTH) - gap;
- if (size > 0) {
- buffer = (const void *)interface.ssm(SCI_GETRANGEPOINTER,
- gap, size);
- if (!fwrite(buffer, size, 1, file)) {
- fclose(file);
- return false;
- }
- }
-
- /* if file existed but has been renamed, restore attributes */
- if (attributes != INVALID_FILE_ATTRIBUTES)
- set_file_attributes(current->filename, attributes);
-#ifdef G_OS_UNIX
- /*
- * only a good try to inherit owner since process user must have
- * CHOWN capability traditionally reserved to root only.
- * That's why we don't handle the return value and are spammed
- * with unused-result warnings by GCC. There is NO sane way to avoid
- * this warning except, adding -Wno-unused-result which disabled all
- * such warnings.
- */
- fchown(fileno(file), file_stat.st_uid, file_stat.st_gid);
-#endif
-
- fclose(file);
-
- return true;
-}
-
void
Ring::close(Buffer *buffer)
{
@@ -524,62 +260,6 @@ Ring::~Ring()
}
/*
- * Auxiliary functions
- */
-#ifdef G_OS_UNIX
-
-gchar *
-get_absolute_path(const gchar *path)
-{
- gchar buf[PATH_MAX];
- gchar *resolved;
-
- if (!path)
- return NULL;
-
- if (!realpath(path, buf)) {
- if (g_path_is_absolute(path)) {
- resolved = g_strdup(path);
- } else {
- gchar *cwd = g_get_current_dir();
- resolved = g_build_filename(cwd, path, NIL);
- g_free(cwd);
- }
- } else {
- resolved = g_strdup(buf);
- }
-
- return resolved;
-}
-
-#elif defined(G_OS_WIN32)
-
-gchar *
-get_absolute_path(const gchar *path)
-{
- TCHAR buf[MAX_PATH];
- gchar *resolved = NULL;
-
- if (path && GetFullPathName(path, sizeof(buf), buf, NULL))
- resolved = g_strdup(buf);
-
- return resolved;
-}
-
-#else
-
-/*
- * FIXME: I doubt that works on any platform...
- */
-gchar *
-get_absolute_path(const gchar *path)
-{
- return path ? g_file_read_link(path, NULL) : NULL;
-}
-
-#endif /* !G_OS_UNIX && !G_OS_WIN32 */
-
-/*
* Command states
*/
@@ -707,7 +387,7 @@ StateEditFile::done(const gchar *str)
* save point files.
* It does not merely overwrite existing files when saving
* but moves them to save point files instead.
- * Save point files are called \(lq.teco-<filename>-<n>\(rq
+ * Save point files are called \(lq.teco-\fIn\fP-\fIfilename\fP\(rq,
* where <filename> is the name of the saved file and <n> is
* a number that is increased with every save operation.
* Save point files are always created in the same directory
@@ -730,8 +410,11 @@ StateSaveFile::done(const gchar *str)
{
BEGIN_EXEC(&States::start);
- if (!ring.save(*str ? str : NULL))
- throw Error("Unable to save file");
+ if (QRegisters::current)
+ throw Error("Cannot save Q-Register");
+// QRegisters::current->save(str);
+ else
+ ring.current->save(*str ? str : NULL);
return &States::start;
}