aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/cmdline.cpp1
-rw-r--r--src/glob.cpp152
-rw-r--r--src/glob.h66
-rw-r--r--src/parser.cpp2
-rw-r--r--src/ring.cpp41
-rw-r--r--src/ring.h6
7 files changed, 231 insertions, 38 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index af324e0..d02c0b5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,7 @@ libsciteco_base_a_SOURCES = main.cpp sciteco.h \
parser.cpp parser.h \
search.cpp search.h \
spawn.cpp spawn.h \
+ glob.cpp glob.h \
goto.cpp goto.h \
rbtree.cpp rbtree.h \
symbols.cpp symbols.h \
diff --git a/src/cmdline.cpp b/src/cmdline.cpp
index e78db60..8b2d412 100644
--- a/src/cmdline.cpp
+++ b/src/cmdline.cpp
@@ -36,6 +36,7 @@
#include "undo.h"
#include "symbols.h"
#include "spawn.h"
+#include "glob.h"
#include "error.h"
#include "cmdline.h"
diff --git a/src/glob.cpp b/src/glob.cpp
new file mode 100644
index 0000000..71100b7
--- /dev/null
+++ b/src/glob.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2012-2014 Robin Haberkorn
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "sciteco.h"
+#include "interface.h"
+#include "parser.h"
+#include "ring.h"
+#include "glob.h"
+
+namespace SciTECO {
+
+namespace States {
+ StateGlob glob;
+}
+
+Globber::Globber(const gchar *_pattern)
+{
+ gchar *basename;
+
+ dirname = g_path_get_dirname(_pattern);
+ dir = g_dir_open(dirname, 0, NULL);
+
+ basename = g_path_get_basename(_pattern);
+ pattern = g_pattern_spec_new(basename);
+ g_free(basename);
+}
+
+gchar *
+Globber::next(void)
+{
+ const gchar *basename;
+
+ while ((basename = g_dir_read_name(dir)))
+ if (g_pattern_match_string(pattern, basename))
+ return g_build_filename(dirname, basename, NIL);
+
+ return NULL;
+}
+
+Globber::~Globber()
+{
+ if (pattern)
+ g_pattern_spec_free(pattern);
+ if (dir)
+ g_dir_close(dir);
+ g_free(dirname);
+}
+
+/*
+ * Command States
+ */
+
+/*$
+ * EN[pattern]$ -- Get list of files matching a glob pattern
+ *
+ * The EN command expands a glob \fIpattern\fP to a list of
+ * matching file names. This is similar to globbing
+ * on UNIX but not as powerful.
+ * A \fIpattern\fP is a file name with \(lq*\(rq and
+ * \(lq?\(rq wildcards:
+ * \(lq*\(rq matches an arbitrary, possibly empty, string.
+ * \(lq?\(rq matches an arbitrary character.
+ *
+ * EN will currently only match files in the file name component
+ * of \fIpattern\fP, not on each component of the path name
+ * separately.
+ * In other words, EN only looks through the directory
+ * of \fIpattern\fP \(em you cannot effectively match
+ * multiple directories.
+ *
+ * The result of the globbing is inserted into the current
+ * document, at the current position.
+ * A linefeed is inserted after every file name, i.e.
+ * every matching file will be on its own line.
+ *
+ * String-building characters are enabled for EN.
+ */
+/*
+ * NOTE: This does not work like classic TECO's
+ * EN command (iterative globbing), since the
+ * position in the directory cannot be reasonably
+ * reset on rubout with glib's API.
+ * If we have to perform all the globbing on initialization
+ * we can just as well return all the results at once.
+ * And we can add them to the current document since
+ * when they should be in a register, the user will
+ * have to edit that register anyway.
+ */
+State *
+StateGlob::done(const gchar *str)
+{
+ BEGIN_EXEC(&States::start);
+
+ Globber globber(str);
+
+ gchar *filename;
+ bool text_added = false;
+
+ interface.ssm(SCI_BEGINUNDOACTION);
+
+ while ((filename = globber.next())) {
+ size_t len = strlen(filename);
+ /* overwrite trailing null */
+ filename[len] = '\n';
+
+ /*
+ * FIXME: Once we're 8-bit clean, we should
+ * add the filenames null-terminated
+ * (there may be linebreaks in filename).
+ */
+ interface.ssm(SCI_ADDTEXT, len+1,
+ (sptr_t)filename);
+
+ g_free(filename);
+ text_added = true;
+ }
+
+ interface.ssm(SCI_SCROLLCARET);
+ interface.ssm(SCI_ENDUNDOACTION);
+
+ if (text_added) {
+ ring.dirtify();
+ if (current_doc_must_undo())
+ interface.undo_ssm(SCI_UNDO);
+ }
+
+ return &States::start;
+}
+
+} /* namespace SciTECO */
diff --git a/src/glob.h b/src/glob.h
new file mode 100644
index 0000000..6652d1d
--- /dev/null
+++ b/src/glob.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012-2014 Robin Haberkorn
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GLOB_H
+#define __GLOB_H
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "sciteco.h"
+#include "parser.h"
+
+namespace SciTECO {
+
+/*
+ * Auxiliary functions
+ */
+static inline bool
+is_glob_pattern(const gchar *str)
+{
+ return strchr(str, '*') || strchr(str, '?');
+}
+
+class Globber {
+ gchar *dirname;
+ GDir *dir;
+ GPatternSpec *pattern;
+
+public:
+ Globber(const gchar *pattern);
+ ~Globber();
+
+ gchar *next(void);
+};
+
+/*
+ * Command states
+ */
+
+class StateGlob : public StateExpectFile {
+private:
+ State *done(const gchar *str);
+};
+
+namespace States {
+ extern StateGlob glob;
+}
+
+} /* namespace SciTECO */
+
+#endif
diff --git a/src/parser.cpp b/src/parser.cpp
index 3c991fc..6995a6b 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -37,6 +37,7 @@
#include "symbols.h"
#include "search.h"
#include "spawn.h"
+#include "glob.h"
#include "cmdline.h"
#include "error.h"
@@ -1801,6 +1802,7 @@ StateECommand::StateECommand() : State()
transitions['C'] = &States::executecommand;
transitions['G'] = &States::egcommand;
transitions['M'] = &States::macro_file;
+ transitions['N'] = &States::glob;
transitions['S'] = &States::scintilla_symbols;
transitions['Q'] = &States::eqcommand;
transitions['W'] = &States::savefile;
diff --git a/src/ring.cpp b/src/ring.cpp
index 575d0e7..03cda37 100644
--- a/src/ring.cpp
+++ b/src/ring.cpp
@@ -38,8 +38,9 @@
#include "parser.h"
#include "expressions.h"
#include "qregisters.h"
-#include "ring.h"
+#include "glob.h"
#include "error.h"
+#include "ring.h"
#ifdef HAVE_WINDOWS_H
/* here it shouldn't cause conflicts with other headers */
@@ -600,8 +601,10 @@ StateEditFile::do_edit(tecoInt id)
* Naturally this only has any effect in interactive
* mode.
*
- * <file> may also be a glob-pattern, in which case
+ * <file> may also be a glob pattern, in which case
* all files matching the pattern are opened/edited.
+ * Globbing is performed exactly the same as the
+ * EN command does.
*
* File names of buffers in the ring are normalized
* by making them absolute.
@@ -661,37 +664,11 @@ StateEditFile::done(const gchar *str)
}
if (is_glob_pattern(str)) {
- gchar *dirname;
- GDir *dir;
-
- dirname = g_path_get_dirname(str);
- dir = g_dir_open(dirname, 0, NULL);
-
- if (dir) {
- const gchar *basename;
- GPatternSpec *pattern;
-
- basename = g_path_get_basename(str);
- pattern = g_pattern_spec_new(basename);
- g_free((gchar *)basename);
-
- while ((basename = g_dir_read_name(dir))) {
- if (g_pattern_match_string(pattern, basename)) {
- gchar *filename;
-
- filename = g_build_filename(dirname,
- basename,
- NIL);
- do_edit(filename);
- g_free(filename);
- }
- }
-
- g_pattern_spec_free(pattern);
- g_dir_close(dir);
- }
+ Globber globber(str);
+ gchar *filename;
- g_free(dirname);
+ while ((filename = globber.next()))
+ do_edit(filename);
} else {
do_edit(*str ? str : NULL);
}
diff --git a/src/ring.h b/src/ring.h
index 8dc0422..b9e9ced 100644
--- a/src/ring.h
+++ b/src/ring.h
@@ -18,7 +18,6 @@
#ifndef __RING_H
#define __RING_H
-#include <string.h>
#include <bsd/sys/queue.h>
#include <glib.h>
@@ -38,11 +37,6 @@ namespace SciTECO {
/*
* Auxiliary functions
*/
-static inline bool
-is_glob_pattern(const gchar *str)
-{
- return strchr(str, '*') || strchr(str, '?');
-}
/*
* Get absolute/full version of a possibly relative path.