aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c119
1 files changed, 99 insertions, 20 deletions
diff --git a/src/main.c b/src/main.c
index 05f8c41..4d46817 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2025 Robin Haberkorn
+ * Copyright (C) 2012-2026 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
@@ -30,17 +30,24 @@
#include <glib/gprintf.h>
#include <glib/gstdio.h>
+#ifdef G_OS_WIN32
+#include <fcntl.h>
+#include <io.h>
+#endif
+
#ifdef HAVE_SYS_CAPSICUM_H
#include <sys/capsicum.h>
#endif
#include "sciteco.h"
+#include "expressions.h"
#include "file-utils.h"
#include "cmdline.h"
#include "interface.h"
#include "parser.h"
#include "goto.h"
#include "qreg.h"
+#include "view.h"
#include "ring.h"
#include "undo.h"
#include "error.h"
@@ -107,6 +114,10 @@ teco_get_default_config_path(void)
#endif
+static gboolean teco_show_version = FALSE;
+static gboolean teco_quiet = FALSE;
+static gboolean teco_stdin = FALSE;
+static gboolean teco_stdout = FALSE;
static gchar *teco_eval_macro = NULL;
static gboolean teco_mung_file = FALSE;
static gboolean teco_mung_profile = TRUE;
@@ -118,6 +129,14 @@ static gchar *
teco_process_options(gchar ***argv)
{
static const GOptionEntry option_entries[] = {
+ {"version", 'v', 0, G_OPTION_ARG_NONE, &teco_show_version,
+ "Show version"},
+ {"quiet", 'q', 0, G_OPTION_ARG_NONE, &teco_quiet,
+ "Don't print any non-user-level messages to stdout"},
+ {"stdin", 'i', 0, G_OPTION_ARG_NONE, &teco_stdin,
+ "Read stdin into the unnamed buffer"},
+ {"stdout", 'o', 0, G_OPTION_ARG_NONE, &teco_stdout,
+ "Print current buffer to stdout before program termination"},
{"eval", 'e', 0, G_OPTION_ARG_STRING, &teco_eval_macro,
"Evaluate macro", "macro"},
{"mung", 'm', 0, G_OPTION_ARG_NONE, &teco_mung_file,
@@ -150,7 +169,7 @@ teco_process_options(gchar ***argv)
g_option_context_set_description(
options,
"Bug reports should go to <" PACKAGE_BUGREPORT "> or "
- "<" PACKAGE_URL ">."
+ "<rhaberkorn@fmsbw.de>."
);
g_option_context_add_main_entries(options, option_entries, NULL);
@@ -186,6 +205,15 @@ teco_process_options(gchar ***argv)
exit(EXIT_FAILURE);
}
+ if (teco_show_version) {
+ puts(PACKAGE_VERSION);
+ exit(EXIT_SUCCESS);
+ }
+
+ if (teco_quiet)
+ /* warnings and errors will still be printed to stderr */
+ teco_interface_msg_level = TECO_MSG_WARNING;
+
if ((*argv)[0] && !g_strcmp0((*argv)[1], "-S")) {
/* translate -S to --, this is always passed down */
(*argv)[1][1] = '-';
@@ -337,6 +365,21 @@ main(int argc, char **argv)
#endif
{
g_autoptr(GError) error = NULL;
+ teco_int_t ret = EXIT_SUCCESS;
+
+#ifdef G_OS_WIN32
+ /*
+ * Windows might by default perform EOL translations, especially
+ * when writing to stdout, i.e. translate LF to CRLF.
+ * This would break at the very least --stdout, where you are
+ * expected to get the linebreaks configured on the current buffer via EL.
+ * It would also break binary filters on Windows.
+ * Since printing LF to the console is safe nowadays, we just do that
+ * globally.
+ */
+ for (gint fd = 0; fd <= 2; fd++)
+ _setmode(fd, _O_BINARY);
+#endif
#ifdef DEBUG_PAUSE
/* Windows debugging hack (see above) */
@@ -417,15 +460,20 @@ main(int argc, char **argv)
* DEC TECO has them in the global table, though.
*/
/* search string and status register */
- teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_plain_new("_", 1));
+ teco_qreg_table_insert_unique(&teco_qreg_table_globals,
+ teco_qreg_plain_new("_", 1));
/* replacement string register */
- teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_plain_new("-", 1));
+ teco_qreg_table_insert_unique(&teco_qreg_table_globals,
+ teco_qreg_plain_new("-", 1));
/* current document's dot (":") */
- teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_dot_new());
+ teco_qreg_table_insert_unique(&teco_qreg_table_globals,
+ teco_qreg_dot_new());
/* current buffer name and number ("*") */
- teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_bufferinfo_new());
+ teco_qreg_table_insert_unique(&teco_qreg_table_globals,
+ teco_qreg_bufferinfo_new());
/* current working directory ("$") */
- teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_workingdir_new());
+ teco_qreg_table_insert_unique(&teco_qreg_table_globals,
+ teco_qreg_workingdir_new());
/* environment defaults and registers */
teco_initialize_environment();
@@ -438,15 +486,37 @@ main(int argc, char **argv)
}
/*
- * Add remaining arguments to unnamed buffer.
+ * Load stdin into the unnamed buffer.
+ * This will also perform EOL normalization.
+ * This is not done automatically when isatty(0) == 0
+ * since you might want to read from stdin manually (^T).
+ * Loading stdin also won't work if the stream is infinite.
*
- * FIXME: This is not really robust since filenames may contain linefeeds.
- * Also, the Unnamed Buffer should be kept empty for piping.
- * Therefore, it would be best to store the arguments in Q-Regs, e.g. $0,$1,$2...
+ * NOTE: The profile hasn't run yet, so it cannot guess the
+ * documents encoding. This should therefore be done by the profile
+ * for any preexisting unnamed buffer.
+ */
+ if (teco_stdin) {
+ if (!teco_view_load_from_stdin(teco_ring_current->view, TRUE, &error))
+ goto cleanup;
+
+ if (teco_interface_ssm(SCI_GETLENGTH, 0, 0) > 0)
+ teco_ring_dirtify();
+ }
+
+ /*
+ * Initialize the commandline-argument Q-registers (^Ax).
*/
- for (gint i = 1; argv_utf8[i]; i++) {
- teco_interface_ssm(SCI_APPENDTEXT, strlen(argv_utf8[i]), (sptr_t)argv_utf8[i]);
- teco_interface_ssm(SCI_APPENDTEXT, 1, (sptr_t)"\n");
+ for (guint i = 0; argv_utf8[i]; i++) {
+ gchar buf[32+1];
+ gint len = g_snprintf(buf, sizeof(buf), "\1%u", i);
+ g_assert(len < sizeof(buf));
+
+ teco_qreg_t *qreg = teco_qreg_plain_new(buf, len);
+ teco_qreg_table_insert_unique(&teco_qreg_table_globals, qreg);
+ if (!qreg->vtable->set_string(qreg, argv_utf8[i], strlen(argv_utf8[i]),
+ teco_default_codepage(), &error))
+ goto cleanup;
}
/*
@@ -461,7 +531,8 @@ main(int argc, char **argv)
}
g_clear_error(&error);
- if (!teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
+ if (!teco_expressions_pop_num_calc(&ret, EXIT_SUCCESS, &error) ||
+ !teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
goto cleanup;
goto cleanup;
}
@@ -498,8 +569,10 @@ main(int argc, char **argv)
goto cleanup;
g_clear_error(&error);
- if (teco_quit_requested) {
- if (!teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
+ if (teco_ed & TECO_ED_EXIT) {
+ /* exit was requested using the EX command */
+ if (!teco_expressions_pop_num_calc(&ret, EXIT_SUCCESS, &error) ||
+ !teco_ed_hook(TECO_ED_HOOK_QUIT, &error))
goto cleanup;
goto cleanup;
}
@@ -509,7 +582,7 @@ main(int argc, char **argv)
* If munged file didn't quit, switch into interactive mode
*/
/* commandline replacement string register */
- teco_qreg_table_insert(&teco_qreg_table_globals, teco_qreg_plain_new("\e", 1));
+ teco_qreg_table_replace(&teco_qreg_table_globals, teco_qreg_plain_new("\e", 1));
teco_undo_enabled = TRUE;
teco_ring_set_scintilla_undo(TRUE);
@@ -553,8 +626,13 @@ main(int argc, char **argv)
goto cleanup;
cleanup:
- if (error != NULL)
+ if (!error && teco_stdout)
+ teco_view_save_to_stdout(teco_ring_current->view, &error);
+
+ if (error != NULL) {
teco_error_display_full(error);
+ ret = EXIT_FAILURE;
+ }
#ifndef NDEBUG
teco_ring_cleanup();
@@ -562,8 +640,9 @@ cleanup:
teco_qreg_table_clear(&teco_qreg_table_globals);
teco_qreg_stack_clear();
teco_view_free(teco_qreg_view);
+ teco_cmdline_cleanup();
#endif
teco_interface_cleanup();
- return error ? EXIT_FAILURE : EXIT_SUCCESS;
+ return ret;
}