aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/sciteco.1.in24
-rw-r--r--doc/sciteco.7.template51
-rw-r--r--src/interface-curses.cpp19
-rw-r--r--src/ioview.cpp11
-rw-r--r--src/main.cpp36
-rw-r--r--src/parser.cpp28
-rw-r--r--src/qregisters.cpp75
-rw-r--r--src/qregisters.h14
-rw-r--r--src/spawn.cpp17
9 files changed, 227 insertions, 48 deletions
diff --git a/doc/sciteco.1.in b/doc/sciteco.1.in
index 0f091db..ef49579 100644
--- a/doc/sciteco.1.in
+++ b/doc/sciteco.1.in
@@ -149,15 +149,27 @@ environment are inserted into the global Q-Register table.
A dollar sign is prepended before each variable name, so that for
instance the variable \(lqHOME\(rq can be examined by macros by
reading the string-content of Q-Register \(lq$HOME\(rq.
-Changes to these Q-Registers are currently not applied to
-the corresponding environment variables.
.LP
-The following environment variables are initialized with default
-values by \*(ST if they are unset:
+Changes to these environment registers are not applied to
+the process environment for technical reasons.
+Nevertheless, \*(ST will always access the environment registers
+instead of the process environment when it needs to evaluate
+an environment variable internally.
+Furthermore, when spawning subprocesses, \*(ST will export
+all Q-Registers beginning with \(lq$\(rq that do not have
+a \(lq=\(rq in their name into the subprocess environment.
+Therefore, the subset of Q-Registers whose name begins with \(lq$\(rq
+can be considered practically identical to the process environment
+and \*(ST macros can access, modify and extend the environment using
+these registers.
+.LP
+The following environment variables and registers are initialized with
+default values by \*(ST if they are unset:
.TP
.B HOME
Home directory of the current user.
-This may be used e.g. by the \fBFG\fP command.
+This may be used e.g. by the \fBFG\fP command and for
+tilde-expansions.
If unset, it defaults to the current user's home directory
as set by
.BR passwd (5)
@@ -191,7 +203,7 @@ defaults to the standard library installation path at
.
.LP
The \fBHOME\fP, \fBSCITECOCONFIG\fP and \fBSCITECOPATH\fP environment
-variables are canonicalized to absolute paths.
+variables and registers are canonicalized to absolute paths.
Therefore it is possible to define them relative to the
working directory of \*(ST when it starts up while macros
can work with the corresponding registers to locate files
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template
index db31daf..79b2eff 100644
--- a/doc/sciteco.7.template
+++ b/doc/sciteco.7.template
@@ -989,17 +989,26 @@ Macro invocations might create new local Q-Register tables for
the executed code.
\*(ST initializes the Q-Registers \(lqA\(rq to \(lqZ\(rq and
\(lq0\(rq to \(lq9\(rq in every Q-Register table.
-Furthermore \*(ST defines and initializes the following special
-global registers:
+.LP
+There are global Q-Registers with special significance for \*(ST
+because they may be accessed by commands opaquely.
+Some of these registers represent information beyond their
+textual and numeric cells \(em they overwrite default operations
+with custom side-effects in order to support unique idioms.
+Some of the registers with special significance are initialized
+by \*(ST while others must be manually defined.
+The following list is an overview of all special global registers:
.TP 2
.BR _ " (underscore)"
Search string and search condition register.
Also used by the globbing command \fBEN\fP, so it is also
the glob string and condition register.
+It is initialized automatically on startup.
.TP
.BR - " (minus)"
Replacement string register.
Its integer part is currently unused.
+It is initialized automatically on startup.
.TP
.BR * " (asterisk)"
File name (string part) and id (numeric part) of current
@@ -1026,6 +1035,7 @@ temporarily:
.EX
[* ! ...change current buffer... ! ]*
.EE
+The register is initialized automatically on startup.
.TP
.BR $ " (dollar)"
The process' current working directory (string part).
@@ -1047,14 +1057,36 @@ The \(lq$\(rq register may also be edited but changing its
string contents this way has no effect on the current
working directory.
Appending to the \(lq$\(rq register is unsupported.
+The register is initialized automatically on startup.
.TP
.BR $ " (Escape)"
Command-line replacement register.
Its integer part is unused.
+It is initialized automatically on startup.
+.TP
+.BI $ variable
+Global Q-Registers beginning with a dollar sign that
+do not contain any \(lq=\(rq represent the process environment
+(the environment variables).
+The register \(lq$\(rq does \fBnot\fP belong to the process
+environment.
+Some environment variables are initialized with default values
+if the corresponding environment variable is unset and
+some may be accessed internally by \*(ST commands.
+In other respects, the environment registers are ordinary
+non-customized registers that support all operations.
+Their numeric parts are currently unused.
+The mechanisms involved are documented more elaborately in
+.BR sciteco (1).
+.TP
+.BI ^F key
+Function key registers as documented in section
+\fBKEY TRANSLATION\fP.
+Their string-content represents a function key macro
+and their numeric part is a function key mask.
+None of those registers are automatically initialized
+on startup.
.LP
-The \*(ST runtime may access other special Q-Registers
-(e.g. function key macros), but they are not initialized by
-default.
Some commands may create and initialize new registers if
necessary, while it is an error to access undefined registers
for some other commands.
@@ -1297,9 +1329,8 @@ current working directory (as can be set e.g. via the
Nevertheless, \*(ST will function properly after changing
the working directory as \*(ST canonicalizes relative
paths to absolute paths if necessary.
-Both buffer file names and some special environment
-variables (as well as their corresponding Q-Registers)
-documented in
+Both buffer file names and some special Q-Registers
+corresponding to environment variables documented in
.BR sciteco (1)
are canonicalized in this way.
.LP
@@ -1338,7 +1369,7 @@ In \*(ST this expansion takes place \fIafter\fP processing
string building characters.
Unlike the UNIX-shell, \*(ST will only expand the \fIcurrent
user's\fP home directory using the value of the
-\(lqHOME\(rq environment variable.
+\(lq$HOME\(rq environment register.
Thus the \(lq~\fIusername\fP\(rq syntax is \fBnot\fP supported.
.LP
Last but not least, some commands accept glob patterns
@@ -1504,7 +1535,7 @@ Note that, \*(ST itself is designed not to produce non-forward-slash
separators and at least allows the user to generate forward-slashes
in portable macros.
This is not the case, for instance when working with environment
-variables.
+registers.
.TP
.IB n \(dqS
.TQ
diff --git a/src/interface-curses.cpp b/src/interface-curses.cpp
index 5f8a00c..1dcca8f 100644
--- a/src/interface-curses.cpp
+++ b/src/interface-curses.cpp
@@ -178,6 +178,13 @@ InterfaceCurses::init_interactive(void)
void
InterfaceCurses::init_batch(void)
{
+ /*
+ * NOTE: It's still safe to use g_getenv().
+ * Actually the process environment has not yet been
+ * imported into the Q-Register table.
+ * Also, the batch mode initialization will be
+ * simplified soon, anyway.
+ */
const gchar *term = g_getenv("TERM");
/*
@@ -227,7 +234,13 @@ InterfaceCurses::init_interactive(void)
{
const gchar *term = g_getenv("TERM");
- /* at least try to report a broken $TERM */
+ /*
+ * At least try to report a broken $TERM.
+ * g_getenv() may still be used here since we must refer to
+ * same value as used in init_batch() as opposed to the
+ * current value of the "$TERM" register.
+ * Also, this code will have to be simplified soon, anyway.
+ */
if (!term || !*term) {
g_fprintf(stderr, "Error initializing interactive mode: "
"$TERM is unset or empty.\n");
@@ -816,6 +829,10 @@ InterfaceCurses::event_loop_impl(void)
* Set window title to a reasonable default,
* in case it is not reset immediately by the
* shell.
+ * FIXME: It may be unsafe to access $TERM here
+ * and the value of Q-Register $TERM may have
+ * diverged. This should be adapted once we rewrite
+ * batch-mode initialization!
*/
#if !PDCURSES && defined(HAVE_TIGETSTR)
set_window_title(g_getenv("TERM") ? : "");
diff --git a/src/ioview.cpp b/src/ioview.cpp
index e43fc2c..713b3fb 100644
--- a/src/ioview.cpp
+++ b/src/ioview.cpp
@@ -36,6 +36,7 @@
#include "interface.h"
#include "undo.h"
#include "error.h"
+#include "qregisters.h"
#include "ioview.h"
#ifdef HAVE_WINDOWS_H
@@ -675,12 +676,14 @@ IOView::save(const gchar *filename)
*
* This supports only strings with a "~" prefix.
* A user name after "~" is not supported.
- * The $HOME environment variable is used to retrieve
+ * The $HOME environment variable/register is used to retrieve
* the current user's home directory.
*/
gchar *
expand_path(const gchar *path)
{
+ gchar *home, *ret;
+
if (!path)
path = "";
@@ -693,7 +696,11 @@ expand_path(const gchar *path)
* but this ensures that a proper path is constructed even if
* it does (e.g. $HOME is changed later on).
*/
- return g_build_filename(g_getenv("HOME"), path+1, NIL);
+ home = QRegisters::globals["$HOME"]->get_string();
+ ret = g_build_filename(home, path+1, NIL);
+ g_free(home);
+
+ return ret;
}
#ifdef G_OS_UNIX
diff --git a/src/main.cpp b/src/main.cpp
index 6966d22..120d73e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -196,9 +196,15 @@ static inline void
initialize_environment(const gchar *program)
{
gchar *default_configpath, *abs_path;
- gchar **env;
/*
+ * Initialize some "special" environment variables.
+ * For ease of use and because there are no threads yet,
+ * we modify the process environment directly.
+ * Later it is imported into the global Q-Register table
+ * and the process environment should no longer be accessed
+ * directly.
+ *
* Initialize and canonicalize $HOME.
* Therefore we can refer to $HOME as the
* current user's home directory on any platform
@@ -237,20 +243,19 @@ initialize_environment(const gchar *program)
g_setenv("SCITECOPATH", abs_path, TRUE);
g_free(abs_path);
- env = g_listenv();
-
- for (gchar **key = env; *key; key++) {
- gchar name[1 + strlen(*key) + 1];
- QRegister *reg;
-
- name[0] = '$';
- strcpy(name + 1, *key);
-
- reg = QRegisters::globals.insert(name);
- reg->set_string(g_getenv(*key));
- }
-
- g_strfreev(env);
+ /*
+ * Import process environment into global Q-Register
+ * table. While it is safe to use g_setenv() early
+ * on at startup, it might be problematic later on
+ * (e.g. it's non-thread-safe).
+ * Therefore the environment registers in the global
+ * table should be used from now on to set and get
+ * environment variables.
+ * When spawning external processes that should inherit
+ * the environment variables, the environment should
+ * be exported via QRegisters::globals.get_environ().
+ */
+ QRegisters::globals.set_environ();
}
/*
@@ -388,6 +393,7 @@ main(int argc, char **argv)
}
if (!mung_file && mung_profile)
+ /* NOTE: Still safe to use g_getenv() */
mung_file = g_build_filename(g_getenv("SCITECOCONFIG"),
INI_FILE, NIL);
diff --git a/src/parser.cpp b/src/parser.cpp
index 3e3f387..f88ae90 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -1595,16 +1595,18 @@ UndoTokenChangeDir::run(void)
*
* If <directory> is omitted, the working directory
* is changed to the current user's home directory
- * as set by the \fBHOME\fP environment variable.
- * This variable is alwas initialized by \*(ST
+ * as set by the \fBHOME\fP environment variable
+ * (i.e. its corresponding \(lq$HOME\(rq environment
+ * register).
+ * This variable is always initialized by \*(ST
* (see \fBsciteco\fP(1)).
* Therefore the expression \(lqFG\fB$\fP\(rq is
- * roughly equivalent to both \(lqFG~\fB$\fP\(rq and
+ * exactly equivalent to both \(lqFG~\fB$\fP\(rq and
* \(lqFG^EQ[$HOME]\fB$\fP\(rq.
*
* The current working directory is also mapped to
- * the Q-Register \(lq$\(rq (dollar sign) which
- * may be used retrieve the current working directory.
+ * the special global Q-Register \(lq$\(rq (dollar sign)
+ * which may be used retrieve the current working directory.
*
* String-building characters are enabled on this
* command and directories can be tab-completed.
@@ -1612,19 +1614,25 @@ UndoTokenChangeDir::run(void)
State *
StateChangeDir::got_file(const gchar *filename)
{
+ gchar *dir;
+
BEGIN_EXEC(&States::start);
/* passes ownership of string to undo token object */
undo.push(new UndoTokenChangeDir(g_get_current_dir()));
- if (!*filename)
- filename = g_getenv("HOME");
+ dir = *filename ? g_strdup(filename)
+ : QRegisters::globals["$HOME"]->get_string();
- if (g_chdir(filename))
+ if (g_chdir(dir)) {
/* FIXME: Is errno usable on Windows here? */
- throw Error("Cannot change working directory "
- "to \"%s\"", filename);
+ Error err("Cannot change working directory "
+ "to \"%s\"", dir);
+ g_free(dir);
+ throw err;
+ }
+ g_free(dir);
return &States::start;
}
diff --git a/src/qregisters.cpp b/src/qregisters.cpp
index 20c1380..22d7300 100644
--- a/src/qregisters.cpp
+++ b/src/qregisters.cpp
@@ -529,7 +529,80 @@ QRegisterTable::edit(QRegister *reg)
QRegisters::current = reg;
}
-/*
+void
+QRegisterTable::set_environ(void)
+{
+ /*
+ * NOTE: Using g_get_environ() would be more efficient,
+ * but it appears to be broken, at least on Wine
+ * and Windows 2000.
+ */
+ gchar **env = g_listenv();
+
+ for (gchar **key = env; *key; key++) {
+ gchar name[1 + strlen(*key) + 1];
+ QRegister *reg;
+
+ name[0] = '$';
+ strcpy(name + 1, *key);
+
+ reg = insert(name);
+ reg->set_string(g_getenv(*key));
+ }
+
+ g_strfreev(env);
+}
+
+gchar **
+QRegisterTable::get_environ(void)
+{
+ QRegister *first = nfind("$");
+
+ gint envp_len = 1;
+ gchar **envp, **p;
+
+ /*
+ * Iterate over all registers beginning with "$" to
+ * guess the size required for the environment array.
+ * This may waste a few bytes because not __every__
+ * register beginning with "$" is an environment
+ * register.
+ */
+ for (QRegister *cur = first;
+ cur && cur->name[0] == '$';
+ cur = (QRegister *)cur->next())
+ envp_len++;
+
+ p = envp = (gchar **)g_malloc(sizeof(gchar *)*envp_len);
+
+ for (QRegister *cur = first;
+ cur && cur->name[0] == '$';
+ cur = (QRegister *)cur->next()) {
+ gchar *value;
+
+ /*
+ * Ignore the "$" register (not an environment
+ * variable register) and registers whose
+ * name contains "=" (not allowed in environment
+ * variable names).
+ */
+ if (!cur->name[1] || strchr(cur->name+1, '='))
+ continue;
+
+ value = cur->get_string();
+ /* more efficient than g_environ_setenv() */
+ *p++ = g_strconcat(cur->name+1, "=", value, NIL);
+ g_free(value);
+ }
+
+ *p = NULL;
+
+ return envp;
+}
+
+/**
+ * Free resources associated with table.
+ *
* This is similar to RBTree::clear() but
* has the advantage that we can check whether some
* register is currently edited.
diff --git a/src/qregisters.h b/src/qregisters.h
index ec40bb4..0ca230e 100644
--- a/src/qregisters.h
+++ b/src/qregisters.h
@@ -255,6 +255,10 @@ public:
insert(QRegister *reg)
{
reg->must_undo = must_undo;
+ /* FIXME: Returns already existing regs with the same name.
+ This could be used to optimize commands that initialize
+ a register if it does not yet exist (saves one table
+ lookup): */
RBTree::insert(reg);
return reg;
}
@@ -283,6 +287,13 @@ public:
return operator [](buf);
}
+ inline QRegister *
+ nfind(const gchar *name)
+ {
+ QRegister reg(name);
+ return (QRegister *)RBTree::nfind(&reg);
+ }
+
void edit(QRegister *reg);
inline QRegister *
edit(const gchar *name)
@@ -295,6 +306,9 @@ public:
return reg;
}
+ void set_environ(void);
+ gchar **get_environ(void);
+
void clear(void);
};
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 9f951f5..b5d64e9 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -198,6 +198,14 @@ parse_shell_command_line(const gchar *cmdline, GError **error)
* \(lq0,128ED\(rq, and is recommended when writing cross-platform
* macros using the EC command.
*
+ * The spawned process inherits both \*(ST's current working
+ * directory and its environment variables.
+ * More precisely, \*(ST uses its environment registers
+ * to construct the spawned process' environment.
+ * Therefore it is also straight forward to change the working
+ * directory or some environment variable temporarily
+ * for a spawned process.
+ *
* Note that when run interactively and subsequently rubbed
* out, \*(ST can easily undo all changes to the editor
* state.
@@ -211,7 +219,7 @@ parse_shell_command_line(const gchar *cmdline, GError **error)
*
* In interactive mode, \*(ST performs TAB-completion
* of filenames in the <command> string parameter but
- * by doing so does not attempt any escaping of shell-relevant
+ * does not attempt any escaping of shell-relevant
* characters like whitespaces.
*/
StateExecuteCommand::StateExecuteCommand() : StateExpectString()
@@ -308,7 +316,7 @@ StateExecuteCommand::done(const gchar *str)
*/
return &States::start;
- gchar **argv;
+ gchar **argv, **envp;
static const gint flags = G_SPAWN_DO_NOT_REAP_CHILD |
G_SPAWN_SEARCH_PATH |
G_SPAWN_STDERR_TO_DEV_NULL;
@@ -330,11 +338,14 @@ StateExecuteCommand::done(const gchar *str)
if (!argv)
goto gerror;
- g_spawn_async_with_pipes(NULL, argv, NULL, (GSpawnFlags)flags,
+ envp = QRegisters::globals.get_environ();
+
+ g_spawn_async_with_pipes(NULL, argv, envp, (GSpawnFlags)flags,
NULL, NULL, &pid,
&stdin_fd, &stdout_fd, NULL,
&ctx.error);
+ g_strfreev(envp);
g_strfreev(argv);
if (ctx.error)