[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] error messages



* Florian Bruhin <me _at_ the _minus_ compiler _dot_ org> [2012-11-18 00:53:01 +0100]:
> Phew. I thought it wouldn't be much work to add error messages to
> herbstluftwm, turns out it was:

ARGH not again. I really should learn how to use git-send-email.

-- 
() ascii ribbon campaign - stop html mail    www.asciiribbon.org
/\ www.the-compiler.org  | I love long mails http://email.is-not-s.ms/
"Paul Lynde to block..." -- a contestant on "Hollywood Squares" 
From 45b6163f4e47b3d605e976029022c08b45cb8df4 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 15:53:30 +0100
Subject: [PATCH 01/25] Use HERBST_NEED_MORE_ARGS if a cmd needs more args

Now a command returns HERBST_NEED_MORE_ARGS in the specific case when it needs
more arguments, instead of HERBST_INVALID_ARGUMENT. This allows ipc-client to
output an error message in this case.
---
 ipc-client/main.c  | 10 +++++++++-
 src/command.c      |  4 ++--
 src/ipc-protocol.h |  1 +
 src/key.c          |  6 ++----
 src/layout.c       | 13 ++++++-------
 src/main.c         | 11 +++++------
 src/monitor.c      | 20 +++++++++-----------
 src/mouse.c        |  2 +-
 src/rules.c        |  2 +-
 src/settings.c     |  8 ++++----
 src/tag.c          | 10 +++++-----
 11 files changed, 45 insertions(+), 42 deletions(-)

diff --git a/ipc-client/main.c b/ipc-client/main.c
index 14567ab..3f57db7 100644
--- a/ipc-client/main.c
+++ b/ipc-client/main.c
@@ -14,6 +14,7 @@
 #include "ipc-client.h"
 #include "../src/globals.h"
 #include "../src/utils.h"
+#include "../src/ipc-protocol.h"
 
 void print_help(char* command);
 void init_hook_regex(int argc, char* argv[]);
@@ -197,7 +198,14 @@ int main(int argc, char* argv[]) {
             fprintf(stderr, "Error: Could not send command.\n");
             return EXIT_FAILURE;
         }
-        fputs(output->str, stdout);
+        if (command_status == 0) { // success, output to stdout
+            fputs(output->str, stdout);
+        } else if (command_status == HERBST_NEED_MORE_ARGS) { // needs more arguments
+            fputs(output->str, stderr);
+            fprintf(stderr, "%s: not enough arguments\n", argv[arg_index]); // first argument == cmd
+        } else { // other error, output to stderr
+            fputs(output->str, stderr);
+        }
         if (g_ensure_newline) {
             if (output->len > 0 && output->str[output->len - 1] != '\n') {
                 fputs("\n", stdout);
diff --git a/src/command.c b/src/command.c
index badd487..fac10f5 100644
--- a/src/command.c
+++ b/src/command.c
@@ -372,7 +372,7 @@ bool parameter_expected(int argc, char** argv, int pos) {
 int complete_command(int argc, char** argv, GString* output) {
     // usage: complete POSITION command to complete ...
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     // index must be between first and last arg of "command to complete ..."
     int position = CLAMP(atoi(argv[1]), 0, argc-2);
@@ -566,7 +566,7 @@ int command_chain_command(int argc, char** argv, GString* output) {
     cmd = STATIC_TABLE_FIND_STR(Cmd2Condition, g_cmd2condition, cmd, argv[0]);
     (void)SHIFT(argc, argv);
     if (argc <= 1) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     char* separator = argv[0];
     (void)SHIFT(argc, argv);
diff --git a/src/ipc-protocol.h b/src/ipc-protocol.h
index 8038597..be599bd 100644
--- a/src/ipc-protocol.h
+++ b/src/ipc-protocol.h
@@ -30,6 +30,7 @@ enum {
     HERBST_FORBIDDEN,
     HERBST_NO_PARAMETER_EXPECTED,
     HERBST_ENV_UNSET,
+    HERBST_NEED_MORE_ARGS,
 };
 
 #endif
diff --git a/src/key.c b/src/key.c
index 85b030a..55e8a67 100644
--- a/src/key.c
+++ b/src/key.c
@@ -94,8 +94,7 @@ char*   modifiermask2name(unsigned int mask) {
 
 int keybind(int argc, char** argv) {
     if (argc <= 2) {
-        fprintf(stderr, "keybind: not enough arguments\n");
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     KeyBinding new_bind;
     // get keycode
@@ -188,8 +187,7 @@ void handle_key_press(XEvent* ev) {
 
 int keyunbind(int argc, char** argv) {
     if (argc <= 1) {
-        fprintf(stderr, "keybind: not enough arguments\n");
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     // remove all keybinds if wanted
     if (!strcmp(argv[1], "-F") || !strcmp(argv[1], "--all")) {
diff --git a/src/layout.c b/src/layout.c
index 4266637..c476a41 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -634,8 +634,7 @@ int frame_current_cycle_client_layout(int argc, char** argv) {
 int frame_current_set_client_layout(int argc, char** argv) {
     int layout = 0;
     if (argc <= 1) {
-        fprintf(stderr, "set_layout: not enough arguments\n");
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     layout = find_layout_by_name(argv[1]);
     if (layout < 0) {
@@ -903,7 +902,7 @@ int frame_current_set_selection(int argc, char** argv) {
     if (argc >= 2) {
         index = atoi(argv[1]);
     } else {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     // find current selection
     HSFrame* frame = frame_current_selection();
@@ -1145,7 +1144,7 @@ void frame_split(HSFrame* frame, int align, int fraction) {
 int frame_split_command(int argc, char** argv) {
     // usage: split h|v FRACTION
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     int align = ALIGN_VERTICAL;
     if (argv[1][0] == 'h') {
@@ -1167,7 +1166,7 @@ int frame_split_command(int argc, char** argv) {
 int frame_change_fraction_command(int argc, char** argv) {
     // usage: fraction DIRECTION DELTA
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     char direction = argv[1][0];
     double delta_double = atof(argv[2]);
@@ -1316,7 +1315,7 @@ int frame_inner_neighbour_index(HSFrame* frame, char direction) {
 
 int frame_focus_command(int argc, char** argv) {
     // usage: focus [-e|-i] left|right|up|down
-    if (argc < 2) return HERBST_INVALID_ARGUMENT;
+    if (argc < 2) return HERBST_NEED_MORE_ARGS;
     if (!g_cur_frame) {
         fprintf(stderr, "warning: no frame is selected\n");
         return HERBST_UNKNOWN_ERROR;
@@ -1356,7 +1355,7 @@ int frame_focus_command(int argc, char** argv) {
 
 int frame_move_window_command(int argc, char** argv) {
     // usage: move left|right|up|down
-    if (argc < 2) return HERBST_INVALID_ARGUMENT;
+    if (argc < 2) return HERBST_NEED_MORE_ARGS;
     if (!g_cur_frame) {
         fprintf(stderr, "warning: no frame is selected\n");
         return HERBST_UNKNOWN_ERROR;
diff --git a/src/main.c b/src/main.c
index b1b04ad..e59ace5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -203,7 +203,7 @@ int load_command(int argc, char** argv, GString* output) {
     // usage: load TAG LAYOUT
     HSTag* tag = NULL;
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     char* layout_string = argv[1];
     if (argc >= 3) {
@@ -288,8 +288,7 @@ int custom_hook_emit(int argc, char** argv) {
 // spawn() heavily inspired by dwm.c
 int spawn(int argc, char** argv) {
     if (argc < 2) {
-        fprintf(stderr, "spawn: too few parameters\n");
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     if (fork() == 0) {
         // only look in child
@@ -360,7 +359,7 @@ int jumpto_command(int argc, char** argv) {
 
 int getenv_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     char* envvar = getenv(argv[1]);
     if (envvar == NULL) {
@@ -372,7 +371,7 @@ int getenv_command(int argc, char** argv, GString* output) {
 
 int setenv_command(int argc, char** argv) {
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     if (setenv(argv[1], argv[2], 1) != 0) {
         return HERBST_INVALID_ARGUMENT;
@@ -382,7 +381,7 @@ int setenv_command(int argc, char** argv) {
 
 int unsetenv_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     if (unsetenv(argv[1]) != 0) {
         return HERBST_INVALID_ARGUMENT;
diff --git a/src/monitor.c b/src/monitor.c
index e3c84a9..7e798fd 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -254,8 +254,7 @@ static RectList* disjoin_rects(XRectangle* buf, size_t count) {
 int disjoin_rects_command(int argc, char** argv, GString* output) {
     (void)SHIFT(argc, argv);
     if (argc < 1) {
-        g_string_append_printf(output, "At least one rect is required.\n");
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     XRectangle* buf = g_new(XRectangle, argc);
     for (int i = 0; i < argc; i++) {
@@ -276,8 +275,7 @@ int disjoin_rects_command(int argc, char** argv, GString* output) {
 int set_monitor_rects_command(int argc, char** argv, GString* output) {
     (void)SHIFT(argc, argv);
     if (argc < 1) {
-        g_string_append_printf(output, "At least one monitor is required.\n");
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     XRectangle* templates = g_new0(XRectangle, argc);
     for (int i = 0; i < argc; i++) {
@@ -334,7 +332,7 @@ HSMonitor* add_monitor(XRectangle rect, HSTag* tag) {
 int add_monitor_command(int argc, char** argv) {
     // usage: add_monitor RECTANGLE [TAG [PADUP [PADRIGHT [PADDOWN [PADLEFT]]]]]
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     XRectangle rect = parse_rectangle(argv[1]);
     HSTag* tag = NULL;
@@ -367,7 +365,7 @@ int add_monitor_command(int argc, char** argv) {
 int remove_monitor_command(int argc, char** argv) {
     // usage: remove_monitor INDEX
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     int index = atoi(argv[1]);
     return remove_monitor(index);
@@ -409,7 +407,7 @@ int move_monitor_command(int argc, char** argv) {
     // usage: move_monitor INDEX RECT [PADUP [PADRIGHT [PADDOWN [PADLEFT]]]]
     // moves monitor with number to RECT
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     int index = atoi(argv[1]);
     if (index < 0 || index >= g_monitors->len) {
@@ -481,7 +479,7 @@ int monitor_rect_command(int argc, char** argv, GString* output) {
 
 int monitor_set_pad_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     int index = atoi(argv[1]);
     if (index < 0 || index >= g_monitors->len) {
@@ -621,7 +619,7 @@ void monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
 
 int monitor_set_tag_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     HSMonitor* monitor = get_current_monitor();
     HSTag*  tag = find_tag(argv[1]);
@@ -635,7 +633,7 @@ int monitor_set_tag_command(int argc, char** argv) {
 
 int monitor_set_tag_by_index_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     bool skip_visible = false;
     if (argc >= 3 && !strcmp(argv[2], "--skip-visible")) {
@@ -651,7 +649,7 @@ int monitor_set_tag_by_index_command(int argc, char** argv) {
 
 int monitor_focus_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     int new_selection = atoi(argv[1]);
     // really change selection
diff --git a/src/mouse.c b/src/mouse.c
index b2bc9f4..74e6e5f 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -157,7 +157,7 @@ int mouse_binding_equals(MouseBinding* a, MouseBinding* b) {
 
 int mouse_bind_command(int argc, char** argv) {
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     unsigned int modifiers = 0;
     char* string = argv[1];
diff --git a/src/rules.c b/src/rules.c
index 474f09c..78e9a11 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -360,7 +360,7 @@ int rule_add_command(int argc, char** argv) {
 
 int rule_remove_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
 
     if (!strcmp(argv[1], "--all") || !strcmp(argv[1], "-F")) {
diff --git a/src/settings.c b/src/settings.c
index b473bcc..944e37e 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -116,7 +116,7 @@ SettingsPair* settings_find(char* name) {
 
 int settings_set_command(int argc, char** argv) {
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
@@ -155,7 +155,7 @@ int settings_set(SettingsPair* pair, char* value) {
 
 int settings_get(int argc, char** argv, GString* output) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
@@ -172,7 +172,7 @@ int settings_get(int argc, char** argv, GString* output) {
 // toggle integer-like values
 int settings_toggle(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
@@ -209,7 +209,7 @@ bool memberequals_settingspair(void* pmember, void* needle) {
 
 int settings_cycle_value(int argc, char** argv) {
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
diff --git a/src/tag.c b/src/tag.c
index 8c2de3c..a2629d7 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -142,7 +142,7 @@ HSTag* add_tag(char* name) {
 
 int tag_add_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     if (!strcmp("", argv[1])) {
         HSDebug("A empty tag name is not permitted\n");
@@ -155,7 +155,7 @@ int tag_add_command(int argc, char** argv) {
 
 int tag_rename_command(int argc, char** argv) {
     if (argc < 3) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     HSTag* tag = find_tag(argv[1]);
     if (!tag) {
@@ -175,7 +175,7 @@ int tag_remove_command(int argc, char** argv) {
     // it removes an TAG and moves all its wins to TARGET
     // if no TARGET is given, current tag is used
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     HSTag* tag = find_tag(argv[1]);
     HSTag* target = (argc >= 3) ? find_tag(argv[2]) : get_current_monitor()->tag;
@@ -313,7 +313,7 @@ HSTag* find_tag_with_toplevel_frame(HSFrame* frame) {
 
 int tag_move_window_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     HSTag* target = find_tag(argv[1]);
     if (!target) {
@@ -325,7 +325,7 @@ int tag_move_window_command(int argc, char** argv) {
 
 int tag_move_window_by_index_command(int argc, char** argv) {
     if (argc < 2) {
-        return HERBST_INVALID_ARGUMENT;
+        return HERBST_NEED_MORE_ARGS;
     }
     bool skip_visible = false;
     if (argc >= 3 && !strcmp(argv[2], "--skip-visible")) {
-- 
1.8.0

From 8dca6d918ef04d99a17d2d9f0d7955c064f89eab Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 15:57:52 +0100
Subject: [PATCH 02/25] Output error message if command is not found

---
 src/command.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/command.c b/src/command.c
index fac10f5..7d1869c 100644
--- a/src/command.c
+++ b/src/command.c
@@ -211,6 +211,8 @@ int call_command(int argc, char** argv, GString* output) {
         i++;
     }
     if (!bind) {
+        g_string_append_printf(output,
+            "error: Command \"%s\" not found!\n", argv[0]);
         return HERBST_COMMAND_NOT_FOUND;
     }
     int status;
-- 
1.8.0

From 4ea300112d73784261af4887b5f0317e99530c75 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 16:02:56 +0100
Subject: [PATCH 03/25] Add error output for nearly every command

---
 NEWS           |   1 +
 src/key.c      |  13 ++++---
 src/key.h      |   4 +--
 src/layout.c   |  19 ++++++----
 src/layout.h   |   6 ++--
 src/main.c     | 112 ++++++++++++++++++++++++++++++++++-----------------------
 src/monitor.c  |  56 ++++++++++++++++++++++-------
 src/monitor.h  |  18 +++++-----
 src/mouse.c    |  10 ++++--
 src/mouse.h    |   3 +-
 src/rules.c    |  42 +++++++++++++---------
 src/rules.h    |   4 +--
 src/settings.c |  16 +++++++--
 src/settings.h |   6 ++--
 src/tag.c      |  36 +++++++++++++++----
 src/tag.h      |  10 +++---
 16 files changed, 235 insertions(+), 121 deletions(-)

diff --git a/NEWS b/NEWS
index c1f803a..2559bcd 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,7 @@ Changes:
     * new rule: ewmhnotify
     * floating, fullscreen, pseudotile: default to toggle if no argument is
       given
+    * add error messages for herbstclient
 
 Release: 0.4.1 on 2012-08-30
 ----------------------------
diff --git a/src/key.c b/src/key.c
index 55e8a67..2d59c41 100644
--- a/src/key.c
+++ b/src/key.c
@@ -92,19 +92,22 @@ char*   modifiermask2name(unsigned int mask) {
     return NULL;
 }
 
-int keybind(int argc, char** argv) {
+int keybind(int argc, char** argv, GString* output) {
     if (argc <= 2) {
         return HERBST_NEED_MORE_ARGS;
     }
     KeyBinding new_bind;
     // get keycode
     if (!string2key(argv[1], &(new_bind.modifiers), &(new_bind.keysym))) {
+        g_string_append_printf(output,
+            "%s: No such KeySym/modifier!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     KeyCode keycode = XKeysymToKeycode(g_display, new_bind.keysym);
     if (!keycode) {
-        fprintf(stderr, "keybind: no keycode for symbol %s\n",
-            XKeysymToString(new_bind.keysym));
+        g_string_append_printf(output,
+            "%s: no keycode for symbol %s\n",
+            argv[0], XKeysymToString(new_bind.keysym));
         return HERBST_INVALID_ARGUMENT;
     }
     // remove existing binding with same keysym/modifiers
@@ -185,7 +188,7 @@ void handle_key_press(XEvent* ev) {
     }
 }
 
-int keyunbind(int argc, char** argv) {
+int keyunbind(int argc, char** argv, GString* output) {
     if (argc <= 1) {
         return HERBST_NEED_MORE_ARGS;
     }
@@ -198,6 +201,8 @@ int keyunbind(int argc, char** argv) {
     KeySym keysym;
     // get keycode
     if (!string2key(argv[1], &modifiers, &keysym)) {
+        g_string_append_printf(output,
+            "%s: No such KeySym/modifier!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     key_remove_bind_with_keysym(modifiers, keysym);
diff --git a/src/key.h b/src/key.h
index 0c4748d..7a274f0 100644
--- a/src/key.h
+++ b/src/key.h
@@ -24,8 +24,8 @@ char*   modifiermask2name(unsigned int mask);
 
 bool string2modifiers(char* string, unsigned int* modmask);
 bool string2key(char* string, unsigned int* modmask, KeySym* keysym);
-int keybind(int argc, char** argv);
-int keyunbind(int argc, char** argv); //removes a keybinding
+int keybind(int argc, char** argv, GString* output);
+int keyunbind(int argc, char** argv, GString* output); //removes a keybinding
 void keybinding_free(KeyBinding* binding);
 
 int key_list_binds(int argc, char** argv, GString* output);
diff --git a/src/layout.c b/src/layout.c
index c476a41..36f1a5e 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -98,7 +98,7 @@ static void fetch_frame_colors() {
         g_warning("too few characters in setting tree_style\n");
         // ensure that it is long enough
         char* argv[] = { "set", "tree_style", "01234567" };
-        settings_set_command(LENGTH(argv), argv);
+        settings_set_command(LENGTH(argv), argv, NULL);
     }
 }
 
@@ -597,7 +597,8 @@ void frame_apply_floating_layout(HSFrame* frame, HSMonitor* m) {
     }
 }
 
-int frame_current_cycle_client_layout(int argc, char** argv) {
+int frame_current_cycle_client_layout(int argc, char** argv, GString* output) {
+    char* cmd_name = argv[0]; // save this before shifting
     int delta = 1;
     if (argc >= 2) {
         delta = atoi(argv[1]);
@@ -617,6 +618,8 @@ int frame_current_cycle_client_layout(int argc, char** argv) {
         idx %= argc;
         layout_index = find_layout_by_name(argv[idx]);
         if (layout_index < 0) {
+            g_string_append_printf(output,
+                "%s: Invalid layout name \"%s\"\n", cmd_name, argv[idx]);
             return HERBST_INVALID_ARGUMENT;
         }
     } else {
@@ -631,14 +634,15 @@ int frame_current_cycle_client_layout(int argc, char** argv) {
     return 0;
 }
 
-int frame_current_set_client_layout(int argc, char** argv) {
+int frame_current_set_client_layout(int argc, char** argv, GString* output) {
     int layout = 0;
     if (argc <= 1) {
         return HERBST_NEED_MORE_ARGS;
     }
     layout = find_layout_by_name(argv[1]);
     if (layout < 0) {
-        HSDebug("set_layout: invalid layout name \"%s\"\n", argv[1]);
+        g_string_append_printf(output,
+            "%s: invalid layout name \"%s\"\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     if (g_cur_frame && g_cur_frame->type == TYPE_CLIENTS) {
@@ -1163,7 +1167,7 @@ int frame_split_command(int argc, char** argv) {
     return 0;
 }
 
-int frame_change_fraction_command(int argc, char** argv) {
+int frame_change_fraction_command(int argc, char** argv, GString* output) {
     // usage: fraction DIRECTION DELTA
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
@@ -1180,7 +1184,10 @@ int frame_change_fraction_command(int argc, char** argv) {
         case 'r':   break;
         case 'u':   delta *= -1; break;
         case 'd':   break;
-        default:    return HERBST_INVALID_ARGUMENT;
+        default:
+            g_string_append_printf(output,
+                "%s: Invalid direction \"%s\"\n", argv[0], argv[1]);
+            return HERBST_INVALID_ARGUMENT;
     }
     HSFrame* neighbour = frame_neighbour(g_cur_frame, direction);
     if (!neighbour) {
diff --git a/src/layout.h b/src/layout.h
index ea7733b..9503a3f 100644
--- a/src/layout.h
+++ b/src/layout.h
@@ -109,7 +109,7 @@ bool frame_remove_window(HSFrame* frame, Window window);
 void frame_destroy(HSFrame* frame, Window** buf, size_t* count);
 void frame_split(HSFrame* frame, int align, int fraction);
 int frame_split_command(int argc, char** argv);
-int frame_change_fraction_command(int argc, char** argv);
+int frame_change_fraction_command(int argc, char** argv, GString* output);
 
 void frame_apply_layout(HSFrame* frame, XRectangle rect);
 void frame_apply_floating_layout(HSFrame* frame, struct HSMonitor* m);
@@ -153,8 +153,8 @@ int frame_foreach_client(HSFrame* frame, ClientAction action, void* data);
 void frame_apply_client_layout_linear(HSFrame* frame, XRectangle rect, bool vertical);
 void frame_apply_client_layout_horizontal(HSFrame* frame, XRectangle rect);
 void frame_apply_client_layout_vertical(HSFrame* frame, XRectangle rect);
-int frame_current_cycle_client_layout(int argc, char** argv);
-int frame_current_set_client_layout(int argc, char** argv);
+int frame_current_cycle_client_layout(int argc, char** argv, GString* output);
+int frame_current_set_client_layout(int argc, char** argv, GString* output);
 int frame_split_count_to_root(HSFrame* frame, int align);
 
 // returns the Window that is focused
diff --git a/src/main.c b/src/main.c
index e59ace5..a473a65 100644
--- a/src/main.c
+++ b/src/main.c
@@ -29,6 +29,7 @@
 #include <sys/select.h>
 #include <sys/wait.h>
 #include <assert.h>
+#include <errno.h>
 // gui
 #include <X11/Xlib.h>
 #include <X11/Xproto.h>
@@ -59,10 +60,10 @@ int spawn(int argc, char** argv);
 int wmexec(int argc, char** argv);
 static void remove_zombies(int signal);
 int custom_hook_emit(int argc, char** argv);
-int jumpto_command(int argc, char** argv);
+int jumpto_command(int argc, char** argv, GString* output);
 int getenv_command(int argc, char** argv, GString* output);
-int setenv_command(int argc, char** argv);
-int unsetenv_command(int argc, char** argv);
+int setenv_command(int argc, char** argv, GString* output);
+int unsetenv_command(int argc, char** argv, GString* output);
 
 // handler for X-Events
 void buttonpress(XEvent* event);
@@ -92,9 +93,9 @@ CommandBinding g_commands[] = {
     CMD_BIND(             "disjoin_rects",  disjoin_rects_command),
     CMD_BIND(             "list_keybinds",  key_list_binds),
     CMD_BIND(             "list_padding",   list_padding),
-    CMD_BIND_NO_OUTPUT(   "keybind",        keybind),
-    CMD_BIND_NO_OUTPUT(   "keyunbind",      keyunbind),
-    CMD_BIND_NO_OUTPUT(   "mousebind",      mouse_bind_command),
+    CMD_BIND(             "keybind",        keybind),
+    CMD_BIND(             "keyunbind",      keyunbind),
+    CMD_BIND(             "mousebind",      mouse_bind_command),
     CMD_BIND_NO_OUTPUT(   "mouseunbind",    mouse_unbind_all),
     CMD_BIND_NO_OUTPUT(   "spawn",          spawn),
     CMD_BIND_NO_OUTPUT(   "wmexec",         wmexec),
@@ -103,42 +104,42 @@ CommandBinding g_commands[] = {
     CMD_BIND_NO_OUTPUT(   "focus_nth",      frame_current_set_selection),
     CMD_BIND_NO_OUTPUT(   "cycle",          frame_current_cycle_selection),
     CMD_BIND_NO_OUTPUT(   "cycle_all",      cycle_all_command),
-    CMD_BIND_NO_OUTPUT(   "cycle_layout",   frame_current_cycle_client_layout),
+    CMD_BIND(             "cycle_layout",   frame_current_cycle_client_layout),
     CMD_BIND_NO_OUTPUT(   "close",          window_close_current),
     CMD_BIND_NO_OUTPUT(   "close_or_remove",close_or_remove_command),
     CMD_BIND_NO_OUTPUT(   "split",          frame_split_command),
-    CMD_BIND_NO_OUTPUT(   "resize",         frame_change_fraction_command),
+    CMD_BIND(             "resize",         frame_change_fraction_command),
     CMD_BIND_NO_OUTPUT(   "focus",          frame_focus_command),
     CMD_BIND_NO_OUTPUT(   "shift",          frame_move_window_command),
     CMD_BIND_NO_OUTPUT(   "remove",         frame_remove_command),
-    CMD_BIND_NO_OUTPUT(   "set",            settings_set_command),
-    CMD_BIND_NO_OUTPUT(   "toggle",         settings_toggle),
-    CMD_BIND_NO_OUTPUT(   "cycle_value",    settings_cycle_value),
+    CMD_BIND(             "set",            settings_set_command),
+    CMD_BIND(             "toggle",         settings_toggle),
+    CMD_BIND(             "cycle_value",    settings_cycle_value),
     CMD_BIND_NO_OUTPUT(   "cycle_monitor",  monitor_cycle_command),
     CMD_BIND_NO_OUTPUT(   "focus_monitor",  monitor_focus_command),
     CMD_BIND(             "get",            settings_get),
-    CMD_BIND_NO_OUTPUT(   "add",            tag_add_command),
-    CMD_BIND_NO_OUTPUT(   "use",            monitor_set_tag_command),
-    CMD_BIND_NO_OUTPUT(   "use_index",      monitor_set_tag_by_index_command),
-    CMD_BIND_NO_OUTPUT(   "jumpto",         jumpto_command),
+    CMD_BIND(             "add",            tag_add_command),
+    CMD_BIND(             "use",            monitor_set_tag_command),
+    CMD_BIND(             "use_index",      monitor_set_tag_by_index_command),
+    CMD_BIND(             "jumpto",         jumpto_command),
     CMD_BIND(             "floating",       tag_set_floating_command),
     CMD_BIND_NO_OUTPUT(   "fullscreen",     client_set_property_command),
     CMD_BIND_NO_OUTPUT(   "pseudotile",     client_set_property_command),
     CMD_BIND(             "tag_status",     print_tag_status_command),
-    CMD_BIND_NO_OUTPUT(   "merge_tag",      tag_remove_command),
-    CMD_BIND_NO_OUTPUT(   "rename",         tag_rename_command),
-    CMD_BIND_NO_OUTPUT(   "move",           tag_move_window_command),
+    CMD_BIND(             "merge_tag",      tag_remove_command),
+    CMD_BIND(             "rename",         tag_rename_command),
+    CMD_BIND(             "move",           tag_move_window_command),
     CMD_BIND_NO_OUTPUT(   "rotate",         layout_rotate_command),
-    CMD_BIND_NO_OUTPUT(   "move_index",     tag_move_window_by_index_command),
-    CMD_BIND_NO_OUTPUT(   "add_monitor",    add_monitor_command),
-    CMD_BIND_NO_OUTPUT(   "raise_monitor",  monitor_raise_command),
+    CMD_BIND(             "move_index",     tag_move_window_by_index_command),
+    CMD_BIND(             "add_monitor",    add_monitor_command),
+    CMD_BIND(             "raise_monitor",  monitor_raise_command),
     CMD_BIND_NO_OUTPUT(   "remove_monitor", remove_monitor_command),
-    CMD_BIND_NO_OUTPUT(   "move_monitor",   move_monitor_command),
+    CMD_BIND(             "move_monitor",   move_monitor_command),
     CMD_BIND(             "monitor_rect",   monitor_rect_command),
-    CMD_BIND_NO_OUTPUT(   "pad",            monitor_set_pad_command),
+    CMD_BIND(             "pad",            monitor_set_pad_command),
     CMD_BIND_NO_OUTPUT(   "raise",          raise_command),
-    CMD_BIND_NO_OUTPUT(   "rule",           rule_add_command),
-    CMD_BIND_NO_OUTPUT(   "unrule",         rule_remove_command),
+    CMD_BIND(             "rule",           rule_add_command),
+    CMD_BIND(             "unrule",         rule_remove_command),
     CMD_BIND(             "layout",         print_layout_command),
     CMD_BIND(             "stack",          print_stack_command),
     CMD_BIND(             "dump",           print_layout_command),
@@ -146,16 +147,16 @@ CommandBinding g_commands[] = {
     CMD_BIND(             "complete",       complete_command),
     CMD_BIND_NO_OUTPUT(   "lock",           monitors_lock_command),
     CMD_BIND_NO_OUTPUT(   "unlock",         monitors_unlock_command),
-    CMD_BIND_NO_OUTPUT(   "lock_tag",       monitor_lock_tag_command),
-    CMD_BIND_NO_OUTPUT(   "unlock_tag",     monitor_unlock_tag_command),
-    CMD_BIND_NO_OUTPUT(   "set_layout",     frame_current_set_client_layout),
-    CMD_BIND_NO_OUTPUT(   "detect_monitors",detect_monitors_command),
+    CMD_BIND(             "lock_tag",       monitor_lock_tag_command),
+    CMD_BIND(             "unlock_tag",     monitor_unlock_tag_command),
+    CMD_BIND(             "set_layout",     frame_current_set_client_layout),
+    CMD_BIND(             "detect_monitors",detect_monitors_command),
     CMD_BIND(             "chain",          command_chain_command),
     CMD_BIND(             "and",            command_chain_command),
     CMD_BIND(             "or",             command_chain_command),
     CMD_BIND(             "getenv",         getenv_command),
-    CMD_BIND_NO_OUTPUT(   "setenv",         setenv_command),
-    CMD_BIND_NO_OUTPUT(   "unsetenv",       unsetenv_command),
+    CMD_BIND(             "setenv",         setenv_command),
+    CMD_BIND(             "unsetenv",       unsetenv_command),
     {{ NULL }}
 };
 
@@ -184,9 +185,12 @@ int print_layout_command(int argc, char** argv, GString* output) {
     HSTag* tag = NULL;
     if (argc >= 2) {
         tag = find_tag(argv[1]);
-    }
-    // if no tag was found
-    if (!tag) {
+        if (!tag) {
+            g_string_append_printf(output,
+                "%s: error: tag \"%s\" not found!\n", argv[0], argv[1]);
+            return HERBST_INVALID_ARGUMENT;
+        }
+    } else { // use current tag
         HSMonitor* m = get_current_monitor();
         tag = m->tag;
     }
@@ -209,9 +213,12 @@ int load_command(int argc, char** argv, GString* output) {
     if (argc >= 3) {
         tag = find_tag(argv[1]);
         layout_string = argv[2];
-    }
-    // if no tag was found
-    if (!tag) {
+        if (!tag) {
+            g_string_append_printf(output,
+                "load_command: error: tag \"%s\" not found!\n", argv[1]);
+            return HERBST_INVALID_ARGUMENT;
+        }
+    } else { // use current tag
         HSMonitor* m = get_current_monitor();
         tag = m->tag;
     }
@@ -230,6 +237,8 @@ int load_command(int argc, char** argv, GString* output) {
         frame_hide_recursive(tag->frame);
     }
     if (!rest) {
+        g_string_append_printf(output,
+            "%s: layout \"%s\" unknown\n", argv[0], layout_string);
         return HERBST_INVALID_ARGUMENT;
     }
     if (rest[0] != '\0') { // if string was not parsed completely
@@ -348,13 +357,22 @@ int raise_command(int argc, char** argv) {
     return 0;
 }
 
-int jumpto_command(int argc, char** argv) {
+int jumpto_command(int argc, char** argv, GString* output) {
     HSClient* client = NULL;
     string_to_client((argc > 1) ? argv[1] : "", &client);
     if (client) {
         focus_window(client->window, true, true);
+        return 0;
+    } else {
+        g_string_append_printf(output,
+            "%s: error: Could not find client", argv[0]);
+        if (argc > 1) {
+            g_string_append_printf(output, " \"%s\".\n", argv[1]);
+        } else {
+            g_string_append(output, ".\n");
+        }
+        return HERBST_INVALID_ARGUMENT;
     }
-    return 0;
 }
 
 int getenv_command(int argc, char** argv, GString* output) {
@@ -363,28 +381,34 @@ int getenv_command(int argc, char** argv, GString* output) {
     }
     char* envvar = getenv(argv[1]);
     if (envvar == NULL) {
+        g_string_append_printf(output,
+            "Environment variable \"%s\" is not set!\n", argv[1]);
         return HERBST_ENV_UNSET;
     }
     g_string_append_printf(output, "%s\n", envvar);
     return 0;
 }
 
-int setenv_command(int argc, char** argv) {
+int setenv_command(int argc, char** argv, GString* output) {
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
     }
     if (setenv(argv[1], argv[2], 1) != 0) {
-        return HERBST_INVALID_ARGUMENT;
+        g_string_append_printf(output,
+	    "Could not set environment variable: %s\n", strerror(errno));
+        return HERBST_UNKNOWN_ERROR;
     }
     return 0;
 }
 
-int unsetenv_command(int argc, char** argv) {
+int unsetenv_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
     if (unsetenv(argv[1]) != 0) {
-        return HERBST_INVALID_ARGUMENT;
+        g_string_append_printf(output,
+	    "Could not unset environment variable: %s\n", strerror(errno));
+        return HERBST_UNKNOWN_ERROR;
     }
     return 0;
 }
@@ -697,7 +721,7 @@ void configurenotify(XEvent* event) {
     if (event->xconfigure.window == g_root &&
         settings_find("auto_detect_monitors")->value.i) {
         char* args[] = { "detect_monitors" };
-        detect_monitors_command(LENGTH(args), args);
+        detect_monitors_command(LENGTH(args), args, NULL);
     }
     // HSDebug("name is: ConfigureNotify\n");
 }
diff --git a/src/monitor.c b/src/monitor.c
index 7e798fd..90fdb67 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -283,6 +283,10 @@ int set_monitor_rects_command(int argc, char** argv, GString* output) {
     }
     int status = set_monitor_rects(templates, argc);
     g_free(templates);
+    if (status == HERBST_TAG_IN_USE) {
+        g_string_append_printf(output,
+            "%s: there are not enough free tags!\n", argv[0]);
+    }
     return status;
 }
 
@@ -329,7 +333,7 @@ HSMonitor* add_monitor(XRectangle rect, HSTag* tag) {
     return g_array_index(g_monitors, HSMonitor*, g_monitors->len-1);
 }
 
-int add_monitor_command(int argc, char** argv) {
+int add_monitor_command(int argc, char** argv, GString* output) {
     // usage: add_monitor RECTANGLE [TAG [PADUP [PADRIGHT [PADDOWN [PADLEFT]]]]]
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
@@ -339,16 +343,22 @@ int add_monitor_command(int argc, char** argv) {
     if (argc == 2 || !strcmp("", argv[2])) {
         tag = find_unused_tag();
         if (!tag) {
+            g_string_append_printf(output,
+                "%s: there are not enough free tags!\n", argv[0]);
             return HERBST_TAG_IN_USE;
         }
     }
     else {
         tag = find_tag(argv[2]);
         if (!tag) {
+            g_string_append_printf(output,
+                "%s: The tag \"%s\" does not exist!\n", argv[0], argv[2]);
             return HERBST_INVALID_ARGUMENT;
         }
     }
     if (find_monitor_with_tag(tag)) {
+        g_string_append_printf(output,
+            "%s: The tag \"%s\" is already viewed on a monitor!\n", argv[0], argv[2]);
         return HERBST_TAG_IN_USE;
     }
     HSMonitor* monitor = add_monitor(rect, tag);
@@ -403,7 +413,7 @@ int remove_monitor(int index) {
     return 0;
 }
 
-int move_monitor_command(int argc, char** argv) {
+int move_monitor_command(int argc, char** argv, GString* output) {
     // usage: move_monitor INDEX RECT [PADUP [PADRIGHT [PADDOWN [PADLEFT]]]]
     // moves monitor with number to RECT
     if (argc < 3) {
@@ -411,10 +421,14 @@ int move_monitor_command(int argc, char** argv) {
     }
     int index = atoi(argv[1]);
     if (index < 0 || index >= g_monitors->len) {
+        g_string_append_printf(output,
+            "%s: index %i is out of range!\n", argv[0], index);
         return HERBST_INVALID_ARGUMENT;
     }
     XRectangle rect = parse_rectangle(argv[2]);
     if (rect.width < WINDOW_MIN_WIDTH || rect.height < WINDOW_MIN_HEIGHT) {
+        g_string_append_printf(output,
+            "%s: rectangle is too small!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     // else: just move it:
@@ -444,8 +458,8 @@ int monitor_rect_command(int argc, char** argv, GString* output) {
         if (!strcmp("-p", argv[1])) {
             with_pad = true;
         } else {
-            fprintf(stderr, "monitor_rect_command: invalid argument \"%s\"\n",
-                    argv[1]);
+            g_string_append_printf(output,
+                "%s: invalid argument \"%s\"\n", argv[0], argv[1]);
             return HERBST_INVALID_ARGUMENT;
         }
     }
@@ -455,8 +469,8 @@ int monitor_rect_command(int argc, char** argv, GString* output) {
         if (1 == sscanf(index_str, "%d", &index)) {
             m = monitor_with_index(index);
             if (!m) {
-                fprintf(stderr,"monitor_rect_command: invalid index \"%s\"\n",
-                        index_str);
+                g_string_append_printf(output,
+                    "%s: invalid index \"%s\"\n", argv[0], index_str);
                 return HERBST_INVALID_ARGUMENT;
             }
         }
@@ -477,12 +491,14 @@ int monitor_rect_command(int argc, char** argv, GString* output) {
     return 0;
 }
 
-int monitor_set_pad_command(int argc, char** argv) {
+int monitor_set_pad_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
     int index = atoi(argv[1]);
     if (index < 0 || index >= g_monitors->len) {
+        g_string_append_printf(output,
+            "%s: index %i is out of range!\n", argv[0], index);
         return HERBST_INVALID_ARGUMENT;
     }
     HSMonitor* monitor = monitor_with_index(index);
@@ -617,7 +633,7 @@ void monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
     emit_tag_changed(tag, g_cur_monitor);
 }
 
-int monitor_set_tag_command(int argc, char** argv) {
+int monitor_set_tag_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
@@ -627,11 +643,13 @@ int monitor_set_tag_command(int argc, char** argv) {
         monitor_set_tag(monitor, tag);
         return 0;
     } else {
+        g_string_append_printf(output,
+            "%s: Invalid monitor or tag!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
 }
 
-int monitor_set_tag_by_index_command(int argc, char** argv) {
+int monitor_set_tag_by_index_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
@@ -641,6 +659,8 @@ int monitor_set_tag_by_index_command(int argc, char** argv) {
     }
     HSTag* tag = get_tag_by_index_str(argv[1], skip_visible);
     if (!tag) {
+        g_string_append_printf(output,
+            "%s: Invalid index \"%s\"!\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     monitor_set_tag(get_current_monitor(), tag);
@@ -811,7 +831,7 @@ void monitors_lock_changed() {
     }
 }
 
-int monitor_lock_tag_command(int argc, char** argv) {
+int monitor_lock_tag_command(int argc, char** argv, GString* output) {
     (void)SHIFT(argc, argv);
     HSMonitor *monitor;
     if (argc >= 1) {
@@ -820,13 +840,15 @@ int monitor_lock_tag_command(int argc, char** argv) {
         monitor = get_current_monitor();
     }
     if (!monitor) {
+        g_string_append_printf(output,
+            "%s: Invalid monitor!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     monitor->lock_tag = true;
     return 0;
 }
 
-int monitor_unlock_tag_command(int argc, char** argv) {
+int monitor_unlock_tag_command(int argc, char** argv, GString* output) {
     (void)SHIFT(argc, argv);
     HSMonitor *monitor;
     if (argc >= 1) {
@@ -835,6 +857,8 @@ int monitor_unlock_tag_command(int argc, char** argv) {
         monitor = get_current_monitor();
     }
     if (!monitor) {
+        g_string_append_printf(output,
+            "%s: Invalid monitor!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     monitor->lock_tag = false;
@@ -904,7 +928,7 @@ bool detect_monitors_simple(XRectangle** ret_rects, size_t* ret_count) {
     return true;
 }
 
-int detect_monitors_command(int argc, char **argv) {
+int detect_monitors_command(int argc, char **argv, GString* output) {
     MonitorDetection detect[] = {
         detect_monitors_xinerama,
         detect_monitors_simple,
@@ -923,6 +947,10 @@ int detect_monitors_command(int argc, char **argv) {
     // apply it
     int ret = set_monitor_rects(monitors, count);
     g_free(monitors);
+    if (ret == HERBST_TAG_IN_USE && output != NULL) {
+        g_string_append_printf(output,
+            "%s: there are not enough free tags!\n", argv[0]);
+    }
     return ret;
 }
 
@@ -938,7 +966,7 @@ HSStack* get_monitor_stack() {
     return g_monitor_stack;
 }
 
-int monitor_raise_command(int argc, char** argv) {
+int monitor_raise_command(int argc, char** argv, GString* output) {
     (void)SHIFT(argc, argv);
     HSMonitor* monitor;
     if (argc >= 1) {
@@ -947,6 +975,8 @@ int monitor_raise_command(int argc, char** argv) {
         monitor = get_current_monitor();
     }
     if (!monitor) {
+        g_string_append_printf(output,
+            "%s: Invalid monitor!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     stack_raise_slide(g_monitor_stack, monitor->slice);
diff --git a/src/monitor.h b/src/monitor.h
index 98cd24d..212d9f9 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -55,8 +55,8 @@ int monitor_get_relative_y(HSMonitor* m, int y_root);
 int monitor_index_of(HSMonitor* monitor);
 int monitor_cycle_command(int argc, char** argv);
 int monitor_focus_command(int argc, char** argv);
-int add_monitor_command(int argc, char** argv);
-int monitor_raise_command(int argc, char** argv);
+int add_monitor_command(int argc, char** argv, GString* output);
+int monitor_raise_command(int argc, char** argv, GString* output);
 int remove_monitor_command(int argc, char** argv);
 int remove_monitor(int index);
 int list_monitors(int argc, char** argv, GString* output);
@@ -64,19 +64,19 @@ int list_padding(int argc, char** argv, GString* output);
 int set_monitor_rects_command(int argc, char** argv, GString* output);
 int disjoin_rects_command(int argc, char** argv, GString* output);
 int set_monitor_rects(XRectangle* templates, size_t count);
-int move_monitor_command(int argc, char** argv);
+int move_monitor_command(int argc, char** argv, GString* output);
 int monitor_rect_command(int argc, char** argv, GString* output);
 HSMonitor* get_current_monitor();
 int monitor_count();
 void monitor_set_tag(HSMonitor* monitor, struct HSTag* tag);
-int monitor_set_pad_command(int argc, char** argv);
-int monitor_set_tag_command(int argc, char** argv);
-int monitor_set_tag_by_index_command(int argc, char** argv);
+int monitor_set_pad_command(int argc, char** argv, GString* output);
+int monitor_set_tag_command(int argc, char** argv, GString* output);
+int monitor_set_tag_by_index_command(int argc, char** argv, GString* output);
 int monitors_lock_command(int argc, char** argv);
 int monitors_unlock_command(int argc, char** argv);
 void monitors_lock_changed();
-int monitor_lock_tag_command(int argc, char** argv);
-int monitor_unlock_tag_command(int argc, char** argv);
+int monitor_lock_tag_command(int argc, char** argv, GString* output);
+int monitor_unlock_tag_command(int argc, char** argv, GString* output);
 void monitor_apply_layout(HSMonitor* monitor);
 void all_monitors_apply_layout();
 void ensure_monitors_are_available();
@@ -90,7 +90,7 @@ struct HSStack* get_monitor_stack();
 typedef bool (*MonitorDetection)(XRectangle**, size_t*);
 bool detect_monitors_xinerama(XRectangle** ret_rects, size_t* ret_count);
 bool detect_monitors_simple(XRectangle** ret_rects, size_t* ret_count);
-int detect_monitors_command(int argc, char **argv);
+int detect_monitors_command(int argc, char **argv, GString* output);
 
 #endif
 
diff --git a/src/mouse.c b/src/mouse.c
index 74e6e5f..dac1c9e 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -155,25 +155,29 @@ int mouse_binding_equals(MouseBinding* a, MouseBinding* b) {
     }
 }
 
-int mouse_bind_command(int argc, char** argv) {
+int mouse_bind_command(int argc, char** argv, GString* output) {
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
     }
     unsigned int modifiers = 0;
     char* string = argv[1];
     if (!string2modifiers(string, &modifiers)) {
+        g_string_append_printf(output,
+            "%s: Modifier \"%s\" does not exist!\n", argv[0], string);
         return HERBST_INVALID_ARGUMENT;
     }
     // last one is the mouse button
     char* last_token = strlasttoken(string, KEY_COMBI_SEPARATORS);
     unsigned int button = string2button(last_token);
     if (button == 0) {
-        fprintf(stderr, "warning: unknown mouse button \"%s\"\n", last_token);
+        g_string_append_printf(output,
+            "%s: Unknown mouse button \"%s\"!\n", argv[0], last_token);
         return HERBST_INVALID_ARGUMENT;
     }
     MouseFunction function = string2mousefunction(argv[2]);
     if (!function) {
-        fprintf(stderr, "warning: unknown mouse action \"%s\"\n", argv[2]);
+        g_string_append_printf(output,
+            "%s: Unknown mouse action \"%s\"!\n", argv[0], argv[2]);
         return HERBST_INVALID_ARGUMENT;
     }
     mouse_bind_function(modifiers, button, function);
diff --git a/src/mouse.h b/src/mouse.h
index cff847c..ca5bee2 100644
--- a/src/mouse.h
+++ b/src/mouse.h
@@ -8,6 +8,7 @@
 
 #include <X11/Xlib.h>
 #include <stdbool.h>
+#include <glib.h>
 
 // various snap-flags
 enum SnapFlags {
@@ -39,7 +40,7 @@ int mouse_binding_equals(MouseBinding* a, MouseBinding* b);
 
 void mouse_bind_function(unsigned int modifiers, unsigned int button,
                          MouseFunction function);
-int mouse_bind_command(int argc, char** argv);
+int mouse_bind_command(int argc, char** argv, GString* output);
 int mouse_unbind_all();
 MouseBinding* mouse_binding_find(unsigned int modifiers, unsigned int button);
 
diff --git a/src/rules.c b/src/rules.c
index 78e9a11..5d18dc2 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -114,10 +114,11 @@ int find_condition_type(char* name) {
     return -1;
 }
 
-HSCondition* condition_create(int type, char op, char* value) {
+HSCondition* condition_create(int type, char op, char* value, GString* output) {
     HSCondition cond;
     if (op != '=' && type == g_maxage_type) {
-        fprintf(stderr, "condition maxage only supports the = operator\n");
+        g_string_append_printf(output,
+            "condition maxage only supports the = operator\n");
         return NULL;
     }
     switch (op) {
@@ -125,7 +126,8 @@ HSCondition* condition_create(int type, char op, char* value) {
             if (type == g_maxage_type) {
                 cond.value_type = CONDITION_VALUE_TYPE_INTEGER;
                 if (1 != sscanf(value, "%d", &cond.value.integer)) {
-                    fprintf(stderr, "cannot integer from \"%s\"\n", value);
+                    g_string_append_printf(output,
+                        "cannot integer from \"%s\"\n", value);
                     return NULL;
                 }
             } else {
@@ -140,16 +142,16 @@ HSCondition* condition_create(int type, char op, char* value) {
             if (status != 0) {
                 char buf[ERROR_STRING_BUF_SIZE];
                 regerror(status, &cond.value.exp, buf, ERROR_STRING_BUF_SIZE);
-                fprintf(stderr, "Cannot parse value \"%s\"", value);
-                fprintf(stderr, "from condition \"%s\": ",
-                        g_condition_types[type].name);
-                fprintf(stderr, "\"%s\"\n", buf);
+                g_string_append_printf(output,
+                    "Cannot parse value \"%s\" from condition \"%s\": \"%s\"\n",
+                    value, g_condition_types[type].name, buf);
                 return NULL;
             }
             break;
 
         default:
-            fprintf(stderr, "unknown rule condition operation \"%c\"\n", op);
+            g_string_append_printf(output,
+                "unknown rule condition operation \"%c\"\n", op);
             return NULL;
             break;
     }
@@ -194,7 +196,7 @@ int find_consequence_type(char* name) {
     return -1;
 }
 
-HSConsequence* consequence_create(int type, char op, char* value) {
+HSConsequence* consequence_create(int type, char op, char* value, GString* output) {
     HSConsequence cons;
     switch (op) {
         case '=':
@@ -203,7 +205,8 @@ HSConsequence* consequence_create(int type, char op, char* value) {
             break;
 
         default:
-            fprintf(stderr, "unknown rule consequence operation \"%c\"\n", op);
+            g_string_append_printf(output,
+                "unknown rule consequence operation \"%c\"\n", op);
             return NULL;
             break;
     }
@@ -288,13 +291,13 @@ static void rule_add_consequence(HSRule* rule, HSConsequence* cons) {
 }
 
 
-int rule_add_command(int argc, char** argv) {
+int rule_add_command(int argc, char** argv, GString* output) {
     // usage: rule COND=VAL ... then
 
     // temporary data structures
     HSRule* rule = rule_create();
     HSCondition* cond;
-    HSConsequence* cons;
+    HSConsequence*  cons;
     bool negated = false;
     struct {
         char* name;
@@ -329,7 +332,7 @@ int rule_add_command(int argc, char** argv) {
         }
 
         else if (consorcond && (type = find_condition_type(name)) >= 0) {
-            cond = condition_create(type, op, value);
+            cond = condition_create(type, op, value, output);
             if (!cond) {
                 rule_destroy(rule);
                 return HERBST_INVALID_ARGUMENT;
@@ -340,7 +343,7 @@ int rule_add_command(int argc, char** argv) {
         }
 
         else if (consorcond && (type = find_consequence_type(name)) >= 0) {
-            cons = consequence_create(type, op, value);
+            cons = consequence_create(type, op, value, output);
             if (!cons) {
                 rule_destroy(rule);
                 return HERBST_INVALID_ARGUMENT;
@@ -349,16 +352,21 @@ int rule_add_command(int argc, char** argv) {
         }
 
         else {
-            fprintf(stderr, "rule: unknown argument \"%s\"\n", *argv);
+            // need to hardcode "rule:" here because args are shifted
+            g_string_append_printf(output,
+                "rule: unknown argument \"%s\"\n", *argv);
             return HERBST_INVALID_ARGUMENT;
         }
     }
 
+    if (output->len > 0) { // if there was output
+        g_string_prepend(output, "rule: ");
+    }
     g_queue_push_tail(&g_rules, rule);
     return 0;
 }
 
-int rule_remove_command(int argc, char** argv) {
+int rule_remove_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
@@ -370,6 +378,8 @@ int rule_remove_command(int argc, char** argv) {
         return 0;
     }
 
+    g_string_append_printf(output,
+        "%s: this command must be used with --all/-F for the time being\n", argv[0]);
     return HERBST_INVALID_ARGUMENT;
 }
 
diff --git a/src/rules.h b/src/rules.h
index d2bb2b7..741ff4b 100644
--- a/src/rules.h
+++ b/src/rules.h
@@ -71,8 +71,8 @@ void client_changes_free_members(HSClientChanges* changes);
 HSRule* rule_create();
 void rule_destroy(HSRule* rule);
 
-int rule_add_command(int argc, char** argv);
-int rule_remove_command(int argc, char** argv);
+int rule_add_command(int argc, char** argv, GString* output);
+int rule_remove_command(int argc, char** argv, GString* output);
 
 #endif
 
diff --git a/src/settings.c b/src/settings.c
index 944e37e..fd0e5d2 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -114,12 +114,16 @@ SettingsPair* settings_find(char* name) {
     return STATIC_TABLE_FIND_STR(SettingsPair, g_settings, name, name);
 }
 
-int settings_set_command(int argc, char** argv) {
+int settings_set_command(int argc, char** argv, GString* output) {
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
+        if (output != NULL) {
+            g_string_append_printf(output,
+                "%s: setting \"%s\" not found!\n", argv[0], argv[1]);
+        }
         return HERBST_SETTING_NOT_FOUND;
     }
     return settings_set(pair, argv[2]);
@@ -159,6 +163,8 @@ int settings_get(int argc, char** argv, GString* output) {
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
+        g_string_append_printf(output,
+            "%s: setting \"%s\" not found!\n", argv[0], argv[1]);
         return HERBST_SETTING_NOT_FOUND;
     }
     if (pair->type == HS_Int) {
@@ -170,12 +176,14 @@ int settings_get(int argc, char** argv, GString* output) {
 }
 
 // toggle integer-like values
-int settings_toggle(int argc, char** argv) {
+int settings_toggle(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
+        g_string_append_printf(output,
+            "%s: setting \"%s\" not found!\n", argv[0], argv[1]);
         return HERBST_SETTING_NOT_FOUND;
     }
     if (pair->type == HS_Int) {
@@ -207,12 +215,14 @@ bool memberequals_settingspair(void* pmember, void* needle) {
     }
 }
 
-int settings_cycle_value(int argc, char** argv) {
+int settings_cycle_value(int argc, char** argv, GString* output) {
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
     }
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
+        g_string_append_printf(output,
+            "%s: setting \"%s\" not found!", argv[0], argv[1]);
         return HERBST_SETTING_NOT_FOUND;
     }
     (void)SHIFT(argc, argv);
diff --git a/src/settings.h b/src/settings.h
index 7b28803..22a7e1b 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -33,9 +33,9 @@ void settings_destroy();
 SettingsPair* settings_find(char* name);
 
 int settings_set(SettingsPair* pair, char* value);
-int settings_set_command(int argc, char** argv);
-int settings_toggle(int argc, char** argv);
-int settings_cycle_value(int argc, char** argv);
+int settings_set_command(int argc, char** argv, GString* output);
+int settings_toggle(int argc, char** argv, GString* output);
+int settings_cycle_value(int argc, char** argv, GString* output);
 int settings_count();
 int settings_get(int argc, char** argv, GString* output);
 
diff --git a/src/tag.c b/src/tag.c
index a2629d7..c7524a2 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -140,12 +140,13 @@ HSTag* add_tag(char* name) {
     return tag;
 }
 
-int tag_add_command(int argc, char** argv) {
+int tag_add_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
     if (!strcmp("", argv[1])) {
-        HSDebug("A empty tag name is not permitted\n");
+        g_string_append_printf(output,
+            "%s: An empty tag name is not permitted\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     HSTag* tag = add_tag(argv[1]);
@@ -153,15 +154,19 @@ int tag_add_command(int argc, char** argv) {
     return 0;
 }
 
-int tag_rename_command(int argc, char** argv) {
+int tag_rename_command(int argc, char** argv, GString* output) {
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
     }
     HSTag* tag = find_tag(argv[1]);
     if (!tag) {
+        g_string_append_printf(output,
+            "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     if (find_tag(argv[2])) {
+        g_string_append_printf(output,
+            "%s: Tag \"%s\" already exists!\n", argv[0], argv[2]);
         return HERBST_TAG_IN_USE;
     }
     g_string_assign(tag->name, argv[2]);
@@ -170,7 +175,7 @@ int tag_rename_command(int argc, char** argv) {
     return 0;
 }
 
-int tag_remove_command(int argc, char** argv) {
+int tag_remove_command(int argc, char** argv, GString* output) {
     // usage: remove TAG [TARGET]
     // it removes an TAG and moves all its wins to TARGET
     // if no TARGET is given, current tag is used
@@ -179,12 +184,23 @@ int tag_remove_command(int argc, char** argv) {
     }
     HSTag* tag = find_tag(argv[1]);
     HSTag* target = (argc >= 3) ? find_tag(argv[2]) : get_current_monitor()->tag;
-    if (!tag || !target || (tag == target)) {
+    if (!tag) {
+        g_string_append_printf(output,
+            "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
+        return HERBST_INVALID_ARGUMENT;
+    } else if (!target) {
+        g_string_append_printf(output,
+            "%s: Tag \"%s\" not found!\n", argv[0], argv[2]);
+    } else if (tag == target) {
+        g_string_append_printf(output,
+            "%s: Cannot merge tag \"%s\" into itself!\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     HSMonitor* monitor = find_monitor_with_tag(tag);
     HSMonitor* monitor_target = find_monitor_with_tag(target);
     if (monitor) {
+        g_string_append_printf(output,
+            "%s: Cannot merge the currently viewed tag!\n", argv[0]);
         return HERBST_TAG_IN_USE;
     }
     // save all these windows
@@ -234,6 +250,8 @@ int tag_set_floating_command(int argc, char** argv, GString* output) {
         tag = find_tag(argv[1]);
         action = argv[2];
         if (!tag) {
+            g_string_append_printf(output,
+                "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
             return HERBST_INVALID_ARGUMENT;
         }
     }
@@ -311,19 +329,21 @@ HSTag* find_tag_with_toplevel_frame(HSFrame* frame) {
     return NULL;
 }
 
-int tag_move_window_command(int argc, char** argv) {
+int tag_move_window_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
     HSTag* target = find_tag(argv[1]);
     if (!target) {
+        g_string_append_printf(output,
+            "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     tag_move_focused_client(target);
     return 0;
 }
 
-int tag_move_window_by_index_command(int argc, char** argv) {
+int tag_move_window_by_index_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
@@ -333,6 +353,8 @@ int tag_move_window_by_index_command(int argc, char** argv) {
     }
     HSTag* tag = get_tag_by_index_str(argv[1], skip_visible);
     if (!tag) {
+        g_string_append_printf(output,
+            "%s: Invalid index \"%s\"\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     tag_move_focused_client(tag);
diff --git a/src/tag.h b/src/tag.h
index d066f67..6f66def 100644
--- a/src/tag.h
+++ b/src/tag.h
@@ -36,13 +36,13 @@ HSTag* find_unused_tag();
 HSTag* find_tag_with_toplevel_frame(struct HSFrame* frame);
 HSTag* get_tag_by_index(int index);
 HSTag* get_tag_by_index_str(char* index_str, bool skip_visible_tags);
-int tag_add_command(int argc, char** argv);
-int tag_rename_command(int argc, char** argv);
-int tag_move_window_command(int argc, char** argv);
-int tag_move_window_by_index_command(int argc, char** argv);
+int tag_add_command(int argc, char** argv, GString* output);
+int tag_rename_command(int argc, char** argv, GString* output);
+int tag_move_window_command(int argc, char** argv, GString* output);
+int tag_move_window_by_index_command(int argc, char** argv, GString* output);
 void tag_move_focused_client(HSTag* target);
 void tag_move_client(struct HSClient* client,HSTag* target);
-int tag_remove_command(int argc, char** argv);
+int tag_remove_command(int argc, char** argv, GString* output);
 int tag_set_floating_command(int argc, char** argv, GString* output);
 void tag_update_focus_layer(HSTag* tag);
 void tag_foreach(void (*action)(HSTag*));
-- 
1.8.0

From d877a677ee05bc3bcc522ccf8524c0b48dd3b4f1 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Mon, 12 Nov 2012 22:37:10 +0100
Subject: [PATCH 04/25] Check if the rule command has enough arguments

---
 src/rules.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/rules.c b/src/rules.c
index 5d18dc2..ecacb79 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -294,6 +294,9 @@ static void rule_add_consequence(HSRule* rule, HSConsequence* cons) {
 int rule_add_command(int argc, char** argv, GString* output) {
     // usage: rule COND=VAL ... then
 
+    if (argc < 2) {
+        return HERBST_NEED_MORE_ARGS;
+    }
     // temporary data structures
     HSRule* rule = rule_create();
     HSCondition* cond;
-- 
1.8.0

From 61dd09acf5fdcad7651e54626214b05e658296ed Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Mon, 12 Nov 2012 17:30:13 +0100
Subject: [PATCH 05/25] Return status code in key_remove_bind_with_keysym

---
 src/key.c | 5 +++--
 src/key.h | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/key.c b/src/key.c
index 2d59c41..af7b8b7 100644
--- a/src/key.c
+++ b/src/key.c
@@ -210,19 +210,20 @@ int keyunbind(int argc, char** argv, GString* output) {
     return 0;
 }
 
-void key_remove_bind_with_keysym(unsigned int modifiers, KeySym keysym){
+int key_remove_bind_with_keysym(unsigned int modifiers, KeySym keysym){
     KeyBinding bind;
     bind.modifiers = modifiers;
     bind.keysym = keysym;
     // search this keysym in list and remove it
     GList* element = g_list_find_custom(g_key_binds, &bind, (GCompareFunc)keysym_equals);
     if (!element) {
-        return;
+        return 1;
     }
     KeyBinding* data = element->data;
     keybinding_free(data);
     g_key_binds = g_list_remove_link(g_key_binds, element);
     g_list_free_1(element);
+    return 0;
 }
 
 void regrab_keys() {
diff --git a/src/key.h b/src/key.h
index 7a274f0..9e017cb 100644
--- a/src/key.h
+++ b/src/key.h
@@ -29,7 +29,7 @@ int keyunbind(int argc, char** argv, GString* output); //removes a keybinding
 void keybinding_free(KeyBinding* binding);
 
 int key_list_binds(int argc, char** argv, GString* output);
-void key_remove_bind_with_keysym(unsigned int modifiers, KeySym sym);
+int key_remove_bind_with_keysym(unsigned int modifiers, KeySym sym);
 void key_remove_all_binds();
 GString* keybinding_to_g_string(KeyBinding* binding);
 void key_find_binds(char* needle, GString* output);
-- 
1.8.0

From e15dd2c748320ac38faf0dae1beecadaeb85867e Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 14:41:45 +0100
Subject: [PATCH 06/25] Add error message when an unbound key is unbinded

---
 src/key.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/key.c b/src/key.c
index af7b8b7..6d541e6 100644
--- a/src/key.c
+++ b/src/key.c
@@ -205,7 +205,10 @@ int keyunbind(int argc, char** argv, GString* output) {
             "%s: No such KeySym/modifier!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
-    key_remove_bind_with_keysym(modifiers, keysym);
+    if (key_remove_bind_with_keysym(modifiers, keysym) != 0) {
+        g_string_append_printf(output,
+            "%s: Key \"%s\" is not bound!\n", argv[0], argv[1]);
+    }
     regrab_keys();
     return 0;
 }
-- 
1.8.0

From 60ef324f4381c46bdb845e22a29000082071ebf1 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Wed, 14 Nov 2012 18:57:13 +0100
Subject: [PATCH 07/25] split: print error message if alignment is invalid

---
 src/layout.c | 10 ++++++++--
 src/layout.h |  2 +-
 src/main.c   |  2 +-
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/layout.c b/src/layout.c
index 36f1a5e..0ef9d19 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -1145,7 +1145,7 @@ void frame_split(HSFrame* frame, int align, int fraction) {
     frame->content.layout.fraction = fraction;
 }
 
-int frame_split_command(int argc, char** argv) {
+int frame_split_command(int argc, char** argv, GString* output) {
     // usage: split h|v FRACTION
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
@@ -1153,7 +1153,13 @@ int frame_split_command(int argc, char** argv) {
     int align = ALIGN_VERTICAL;
     if (argv[1][0] == 'h') {
         align = ALIGN_HORIZONTAL;
-    } // else: layout is vertical
+    } else if (argv[1][0] == 'v') {
+        align = ALIGN_VERTICAL;
+    } else {
+        g_string_append_printf(output,
+            "%s: invalid alignment \"%s\"\n", argv[0], argv[1]);
+        return HERBST_INVALID_ARGUMENT;
+    }
     int fraction = FRACTION_UNIT* CLAMP(atof(argv[2]),
                                         0.0 + FRAME_MIN_FRACTION,
                                         1.0 - FRAME_MIN_FRACTION);
diff --git a/src/layout.h b/src/layout.h
index 9503a3f..ebb2882 100644
--- a/src/layout.h
+++ b/src/layout.h
@@ -108,7 +108,7 @@ bool frame_remove_window(HSFrame* frame, Window window);
 // YOU have to g_free the resulting window-buf
 void frame_destroy(HSFrame* frame, Window** buf, size_t* count);
 void frame_split(HSFrame* frame, int align, int fraction);
-int frame_split_command(int argc, char** argv);
+int frame_split_command(int argc, char** argv, GString* output);
 int frame_change_fraction_command(int argc, char** argv, GString* output);
 
 void frame_apply_layout(HSFrame* frame, XRectangle rect);
diff --git a/src/main.c b/src/main.c
index a473a65..6cce92c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -107,7 +107,7 @@ CommandBinding g_commands[] = {
     CMD_BIND(             "cycle_layout",   frame_current_cycle_client_layout),
     CMD_BIND_NO_OUTPUT(   "close",          window_close_current),
     CMD_BIND_NO_OUTPUT(   "close_or_remove",close_or_remove_command),
-    CMD_BIND_NO_OUTPUT(   "split",          frame_split_command),
+    CMD_BIND(             "split",          frame_split_command),
     CMD_BIND(             "resize",         frame_change_fraction_command),
     CMD_BIND_NO_OUTPUT(   "focus",          frame_focus_command),
     CMD_BIND_NO_OUTPUT(   "shift",          frame_move_window_command),
-- 
1.8.0

From c1d6b8d21603aed0f6d6ca93d68e15f57324bb58 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Wed, 14 Nov 2012 19:14:39 +0100
Subject: [PATCH 08/25] Print error when frame neighbours are missing

---
 src/layout.c | 17 +++++++++++++----
 src/layout.h |  4 ++--
 src/main.c   |  4 ++--
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/src/layout.c b/src/layout.c
index 0ef9d19..259d888 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -1207,8 +1207,9 @@ int frame_change_fraction_command(int argc, char** argv, GString* output) {
         }
         neighbour = frame_neighbour(g_cur_frame, direction);
         if (!neighbour) {
-            // nothing to do
-            return 0;
+            g_string_append_printf(output,
+                "%s: No neighbour found!", argv[0]);
+            return HERBST_FORBIDDEN;
         }
     }
     HSFrame* parent = neighbour->parent;
@@ -1326,7 +1327,7 @@ int frame_inner_neighbour_index(HSFrame* frame, char direction) {
     return index;
 }
 
-int frame_focus_command(int argc, char** argv) {
+int frame_focus_command(int argc, char** argv, GString* output) {
     // usage: focus [-e|-i] left|right|up|down
     if (argc < 2) return HERBST_NEED_MORE_ARGS;
     if (!g_cur_frame) {
@@ -1361,12 +1362,16 @@ int frame_focus_command(int argc, char** argv) {
             // change focus if possible
             frame_focus_recursive(parent);
             monitor_apply_layout(get_current_monitor());
+        } else {
+            g_string_append_printf(output,
+                "%s: No neighbour found!", argv[0]);
+            return HERBST_FORBIDDEN;
         }
     }
     return 0;
 }
 
-int frame_move_window_command(int argc, char** argv) {
+int frame_move_window_command(int argc, char** argv, GString* output) {
     // usage: move left|right|up|down
     if (argc < 2) return HERBST_NEED_MORE_ARGS;
     if (!g_cur_frame) {
@@ -1429,6 +1434,10 @@ int frame_move_window_command(int argc, char** argv) {
             }
             // layout was changed, so update it
             monitor_apply_layout(get_current_monitor());
+        } else {
+            g_string_append_printf(output,
+                "%s: No neighbour found!", argv[0]);
+            return HERBST_FORBIDDEN;
         }
     }
     return 0;
diff --git a/src/layout.h b/src/layout.h
index ebb2882..f09a07f 100644
--- a/src/layout.h
+++ b/src/layout.h
@@ -138,7 +138,7 @@ void frame_unfocus(); // unfocus currently focused window
 // returns the neighbour or NULL if there is no one
 HSFrame* frame_neighbour(HSFrame* frame, char direction);
 int frame_inner_neighbour_index(HSFrame* frame, char direction);
-int frame_focus_command(int argc, char** argv);
+int frame_focus_command(int argc, char** argv, GString* output);
 
 // follow selection to leave and focus this frame
 int frame_focus_recursive(HSFrame* frame);
@@ -163,7 +163,7 @@ Window frame_focused_window(HSFrame* frame);
 bool frame_focus_window(HSFrame* frame, Window win);
 bool focus_window(Window win, bool switch_tag, bool switch_monitor);
 // moves a window to an other frame
-int frame_move_window_command(int argc, char** argv);
+int frame_move_window_command(int argc, char** argv, GString* output);
 /// removes the current frame
 int frame_remove_command(int argc, char** argv);
 int close_or_remove_command(int argc, char** argv);
diff --git a/src/main.c b/src/main.c
index 6cce92c..455d800 100644
--- a/src/main.c
+++ b/src/main.c
@@ -109,8 +109,8 @@ CommandBinding g_commands[] = {
     CMD_BIND_NO_OUTPUT(   "close_or_remove",close_or_remove_command),
     CMD_BIND(             "split",          frame_split_command),
     CMD_BIND(             "resize",         frame_change_fraction_command),
-    CMD_BIND_NO_OUTPUT(   "focus",          frame_focus_command),
-    CMD_BIND_NO_OUTPUT(   "shift",          frame_move_window_command),
+    CMD_BIND(             "focus",          frame_focus_command),
+    CMD_BIND(             "shift",          frame_move_window_command),
     CMD_BIND_NO_OUTPUT(   "remove",         frame_remove_command),
     CMD_BIND(             "set",            settings_set_command),
     CMD_BIND(             "toggle",         settings_toggle),
-- 
1.8.0

From 897f49168092d1706747abcbae96bc40a30d089f Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Wed, 14 Nov 2012 19:21:38 +0100
Subject: [PATCH 09/25] bring: add error message when client is invalid

---
 src/layout.c | 9 ++++++++-
 src/layout.h | 2 +-
 src/main.c   | 2 +-
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/layout.c b/src/layout.c
index 259d888..2e016a7 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -889,11 +889,18 @@ HSFrame* frame_current_selection() {
     return frame;
 }
 
-int frame_current_bring(int argc, char** argv) {
+int frame_current_bring(int argc, char** argv, GString* output) {
     HSClient* client = NULL;
 
     string_to_client((argc > 1) ? argv[1] : "", &client);
     if (!client) {
+        g_string_append_printf(output,
+            "%s: error: Could not find client", argv[0]);
+        if (argc > 1) {
+            g_string_append_printf(output, " \"%s\".\n", argv[1]);
+        } else {
+            g_string_append(output, ".\n");
+        }
         return HERBST_INVALID_ARGUMENT;
     }
     tag_move_client(client, get_current_monitor()->tag);
diff --git a/src/layout.h b/src/layout.h
index f09a07f..1336343 100644
--- a/src/layout.h
+++ b/src/layout.h
@@ -127,7 +127,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg);
 int find_layout_by_name(char* name);
 int find_align_by_name(char* name);
 
-int frame_current_bring(int argc, char** argv);
+int frame_current_bring(int argc, char** argv, GString* output);
 int frame_current_set_selection(int argc, char** argv);
 int frame_current_cycle_selection(int argc, char** argv);
 int cycle_all_command(int argc, char** argv);
diff --git a/src/main.c b/src/main.c
index 455d800..1fda630 100644
--- a/src/main.c
+++ b/src/main.c
@@ -100,7 +100,7 @@ CommandBinding g_commands[] = {
     CMD_BIND_NO_OUTPUT(   "spawn",          spawn),
     CMD_BIND_NO_OUTPUT(   "wmexec",         wmexec),
     CMD_BIND_NO_OUTPUT(   "emit_hook",      custom_hook_emit),
-    CMD_BIND_NO_OUTPUT(   "bring",          frame_current_bring),
+    CMD_BIND(             "bring",          frame_current_bring),
     CMD_BIND_NO_OUTPUT(   "focus_nth",      frame_current_set_selection),
     CMD_BIND_NO_OUTPUT(   "cycle",          frame_current_cycle_selection),
     CMD_BIND_NO_OUTPUT(   "cycle_all",      cycle_all_command),
-- 
1.8.0

From c3119791571d0e39f1dd7b04adcf9ef88ccab3ac Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Wed, 14 Nov 2012 20:45:32 +0100
Subject: [PATCH 10/25] Make arguments mandatory in jumpto/bring

When jumpto/bring were called without an argument, they defaulted to "currently
focused client", but that doesn't make sense with these commands.
---
 src/layout.c |  5 ++++-
 src/main.c   | 10 ++++++++--
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/layout.c b/src/layout.c
index 2e016a7..bba2f78 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -892,7 +892,10 @@ HSFrame* frame_current_selection() {
 int frame_current_bring(int argc, char** argv, GString* output) {
     HSClient* client = NULL;
 
-    string_to_client((argc > 1) ? argv[1] : "", &client);
+    if (argc < 2) {
+        return HERBST_NEED_MORE_ARGS;
+    }
+    string_to_client(argv[1], &client);
     if (!client) {
         g_string_append_printf(output,
             "%s: error: Could not find client", argv[0]);
diff --git a/src/main.c b/src/main.c
index 1fda630..1dc8e0d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -346,9 +346,12 @@ int wmexec(int argc, char** argv) {
 }
 
 int raise_command(int argc, char** argv) {
+    if (argc < 2) {
+        return HERBST_NEED_MORE_ARGS;
+    }
     Window win;
     HSClient* client = NULL;
-    win = string_to_client((argc > 1) ? argv[1] : "", &client);
+    win = string_to_client(argv[1], &client);
     if (client) {
         client_raise(client);
     } else {
@@ -358,8 +361,11 @@ int raise_command(int argc, char** argv) {
 }
 
 int jumpto_command(int argc, char** argv, GString* output) {
+    if (argc < 2) {
+        return HERBST_NEED_MORE_ARGS;
+    }
     HSClient* client = NULL;
-    string_to_client((argc > 1) ? argv[1] : "", &client);
+    string_to_client(argv[1], &client);
     if (client) {
         focus_window(client->window, true, true);
         return 0;
-- 
1.8.0

From a6c4ebb2b86954cf4cfeb9f99f244fbac1abd8dd Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 07:01:34 +0100
Subject: [PATCH 11/25] Print help when there are no hc-arguments

---
 ipc-client/main.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ipc-client/main.c b/ipc-client/main.c
index 3f57db7..49f3367 100644
--- a/ipc-client/main.c
+++ b/ipc-client/main.c
@@ -185,6 +185,12 @@ int main(int argc, char* argv[]) {
         }
     }
     int arg_index = optind; // index of the first-non-option argument
+    if ((argc - arg_index == 0) && !g_wait_for_hook) {
+        // if there are no non-option arguments, and no --idle/--wait, display
+        // the help and exit
+        print_help(argv[0]);
+        exit(EXIT_FAILURE);
+    }
     // do communication
     int command_status;
     if (g_wait_for_hook == 1) {
-- 
1.8.0

From f77144993a18db82fd250a0df21b5ed1bb1faced Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 19:29:49 +0100
Subject: [PATCH 12/25] Cleanup of error messages

 - Don't display "error:" anywhere
 - Use argv[0] where possible
 - If argv[0] is not possible, display function-name hardcoded
 - Capitalize first letter after colon
 - Some rewording
 - Always print a newline after output
 - Don't print a exclamation mark at the end
 - Whitespace fixes
---
 src/command.c  |  2 +-
 src/key.c      |  8 ++++----
 src/layout.c   | 24 ++++++++++++------------
 src/main.c     | 16 ++++++++--------
 src/monitor.c  | 30 +++++++++++++++---------------
 src/mouse.c    |  6 +++---
 src/rules.c    | 16 ++++++++--------
 src/settings.c |  8 ++++----
 src/tag.c      | 16 ++++++++--------
 9 files changed, 63 insertions(+), 63 deletions(-)

diff --git a/src/command.c b/src/command.c
index 7d1869c..9a892b4 100644
--- a/src/command.c
+++ b/src/command.c
@@ -212,7 +212,7 @@ int call_command(int argc, char** argv, GString* output) {
     }
     if (!bind) {
         g_string_append_printf(output,
-            "error: Command \"%s\" not found!\n", argv[0]);
+            "error: Command \"%s\" not found\n", argv[0]);
         return HERBST_COMMAND_NOT_FOUND;
     }
     int status;
diff --git a/src/key.c b/src/key.c
index 6d541e6..15e926b 100644
--- a/src/key.c
+++ b/src/key.c
@@ -100,13 +100,13 @@ int keybind(int argc, char** argv, GString* output) {
     // get keycode
     if (!string2key(argv[1], &(new_bind.modifiers), &(new_bind.keysym))) {
         g_string_append_printf(output,
-            "%s: No such KeySym/modifier!\n", argv[0]);
+            "%s: No such KeySym/modifier\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     KeyCode keycode = XKeysymToKeycode(g_display, new_bind.keysym);
     if (!keycode) {
         g_string_append_printf(output,
-            "%s: no keycode for symbol %s\n",
+            "%s: No keycode for symbol %s\n",
             argv[0], XKeysymToString(new_bind.keysym));
         return HERBST_INVALID_ARGUMENT;
     }
@@ -202,12 +202,12 @@ int keyunbind(int argc, char** argv, GString* output) {
     // get keycode
     if (!string2key(argv[1], &modifiers, &keysym)) {
         g_string_append_printf(output,
-            "%s: No such KeySym/modifier!\n", argv[0]);
+            "%s: No such KeySym/modifier\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     if (key_remove_bind_with_keysym(modifiers, keysym) != 0) {
         g_string_append_printf(output,
-            "%s: Key \"%s\" is not bound!\n", argv[0], argv[1]);
+            "%s: Key \"%s\" is not bound\n", argv[0], argv[1]);
     }
     regrab_keys();
     return 0;
diff --git a/src/layout.c b/src/layout.c
index bba2f78..dced9d3 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -345,7 +345,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         if (3 != sscanf(args, "%[^"SEP"]"SEP"%lf"SEP"%d",
             align_name, &fraction_double, &selection)) {
             g_string_append_printf(errormsg,
-                    "cannot parse frame args \"%s\"\n", args);
+                "load: Can not parse frame args \"%s\"\n", args);
             return NULL;
         }
 #undef SEP
@@ -353,7 +353,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         g_free(align_name);
         if (align < 0) {
             g_string_append_printf(errormsg,
-                    "invalid align name in args \"%s\"\n", args);
+                "load: Invalid align name in args \"%s\"\n", args);
             return NULL;
         }
         selection = !!selection; // CLAMP it to [0;1]
@@ -368,7 +368,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
             frame_split(frame, align, fraction);
             if (frame->type != TYPE_FRAMES) {
                 g_string_append_printf(errormsg,
-                    "cannot split frame");
+                    "load: Can not split frame\n");
                 return NULL;
             }
         }
@@ -389,7 +389,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         if (2 != sscanf(args, "%[^"SEP"]"SEP"%d",
             layout_name, &selection)) {
             g_string_append_printf(errormsg,
-                    "cannot parse frame args \"%s\"\n", args);
+                "load: Can not parse frame args \"%s\"\n", args);
             return NULL;
         }
 #undef SEP
@@ -397,7 +397,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         g_free(layout_name);
         if (layout < 0) {
             g_string_append_printf(errormsg,
-                    "cannot parse layout from args \"%s\"\n", args);
+                "load: Can not parse layout from args \"%s\"\n", args);
             return NULL;
         }
 
@@ -434,7 +434,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
             Window win;
             if (1 != sscanf(description, "0x%lx\n", &win)) {
                 g_string_append_printf(errormsg,
-                        "cannot parse window id from \"%s\"\n", description);
+                    "load: Can not parse window id from \"%s\"\n", description);
                 return NULL;
             }
             // jump over window id and over whitespaces
@@ -642,7 +642,7 @@ int frame_current_set_client_layout(int argc, char** argv, GString* output) {
     layout = find_layout_by_name(argv[1]);
     if (layout < 0) {
         g_string_append_printf(output,
-            "%s: invalid layout name \"%s\"\n", argv[0], argv[1]);
+            "%s: Invalid layout name \"%s\"\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     if (g_cur_frame && g_cur_frame->type == TYPE_CLIENTS) {
@@ -898,7 +898,7 @@ int frame_current_bring(int argc, char** argv, GString* output) {
     string_to_client(argv[1], &client);
     if (!client) {
         g_string_append_printf(output,
-            "%s: error: Could not find client", argv[0]);
+            "%s: Could not find client", argv[0]);
         if (argc > 1) {
             g_string_append_printf(output, " \"%s\".\n", argv[1]);
         } else {
@@ -1167,7 +1167,7 @@ int frame_split_command(int argc, char** argv, GString* output) {
         align = ALIGN_VERTICAL;
     } else {
         g_string_append_printf(output,
-            "%s: invalid alignment \"%s\"\n", argv[0], argv[1]);
+            "%s: Invalid alignment \"%s\"\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     int fraction = FRACTION_UNIT* CLAMP(atof(argv[2]),
@@ -1218,7 +1218,7 @@ int frame_change_fraction_command(int argc, char** argv, GString* output) {
         neighbour = frame_neighbour(g_cur_frame, direction);
         if (!neighbour) {
             g_string_append_printf(output,
-                "%s: No neighbour found!", argv[0]);
+                "%s: No neighbour found\n", argv[0]);
             return HERBST_FORBIDDEN;
         }
     }
@@ -1374,7 +1374,7 @@ int frame_focus_command(int argc, char** argv, GString* output) {
             monitor_apply_layout(get_current_monitor());
         } else {
             g_string_append_printf(output,
-                "%s: No neighbour found!", argv[0]);
+                "%s: No neighbour found\n", argv[0]);
             return HERBST_FORBIDDEN;
         }
     }
@@ -1446,7 +1446,7 @@ int frame_move_window_command(int argc, char** argv, GString* output) {
             monitor_apply_layout(get_current_monitor());
         } else {
             g_string_append_printf(output,
-                "%s: No neighbour found!", argv[0]);
+                "%s: No neighbour found\n", argv[0]);
             return HERBST_FORBIDDEN;
         }
     }
diff --git a/src/main.c b/src/main.c
index 1dc8e0d..5b27526 100644
--- a/src/main.c
+++ b/src/main.c
@@ -187,7 +187,7 @@ int print_layout_command(int argc, char** argv, GString* output) {
         tag = find_tag(argv[1]);
         if (!tag) {
             g_string_append_printf(output,
-                "%s: error: tag \"%s\" not found!\n", argv[0], argv[1]);
+                "%s: Tag \"%s\" not found\n", argv[0], argv[1]);
             return HERBST_INVALID_ARGUMENT;
         }
     } else { // use current tag
@@ -215,7 +215,7 @@ int load_command(int argc, char** argv, GString* output) {
         layout_string = argv[2];
         if (!tag) {
             g_string_append_printf(output,
-                "load_command: error: tag \"%s\" not found!\n", argv[1]);
+                "%s: Tag \"%s\" not found\n", argv[0], argv[1]);
             return HERBST_INVALID_ARGUMENT;
         }
     } else { // use current tag
@@ -238,12 +238,12 @@ int load_command(int argc, char** argv, GString* output) {
     }
     if (!rest) {
         g_string_append_printf(output,
-            "%s: layout \"%s\" unknown\n", argv[0], layout_string);
+            "%s: Layout \"%s\" unknown\n", argv[0], layout_string);
         return HERBST_INVALID_ARGUMENT;
     }
     if (rest[0] != '\0') { // if string was not parsed completely
         g_string_append_printf(output,
-            "%s: layout description was too long\n", argv[0]);
+            "%s: Layout description was too long\n", argv[0]);
         g_string_append_printf(output,
             "%s: \"%s\" has not been parsed\n", argv[0], rest);
         return HERBST_INVALID_ARGUMENT;
@@ -371,7 +371,7 @@ int jumpto_command(int argc, char** argv, GString* output) {
         return 0;
     } else {
         g_string_append_printf(output,
-            "%s: error: Could not find client", argv[0]);
+            "%s: Could not find client", argv[0]);
         if (argc > 1) {
             g_string_append_printf(output, " \"%s\".\n", argv[1]);
         } else {
@@ -388,7 +388,7 @@ int getenv_command(int argc, char** argv, GString* output) {
     char* envvar = getenv(argv[1]);
     if (envvar == NULL) {
         g_string_append_printf(output,
-            "Environment variable \"%s\" is not set!\n", argv[1]);
+            "%s: Environment variable \"%s\" is not set\n", argv[0], argv[1]);
         return HERBST_ENV_UNSET;
     }
     g_string_append_printf(output, "%s\n", envvar);
@@ -401,7 +401,7 @@ int setenv_command(int argc, char** argv, GString* output) {
     }
     if (setenv(argv[1], argv[2], 1) != 0) {
         g_string_append_printf(output,
-	    "Could not set environment variable: %s\n", strerror(errno));
+            "%s: Could not set environment variable: %s\n", argv[0], strerror(errno));
         return HERBST_UNKNOWN_ERROR;
     }
     return 0;
@@ -413,7 +413,7 @@ int unsetenv_command(int argc, char** argv, GString* output) {
     }
     if (unsetenv(argv[1]) != 0) {
         g_string_append_printf(output,
-	    "Could not unset environment variable: %s\n", strerror(errno));
+            "%s: Could not unset environment variable: %s\n", argv[0], strerror(errno));
         return HERBST_UNKNOWN_ERROR;
     }
     return 0;
diff --git a/src/monitor.c b/src/monitor.c
index 90fdb67..b641a3d 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -285,7 +285,7 @@ int set_monitor_rects_command(int argc, char** argv, GString* output) {
     g_free(templates);
     if (status == HERBST_TAG_IN_USE) {
         g_string_append_printf(output,
-            "%s: there are not enough free tags!\n", argv[0]);
+            "%s: There are not enough free tags\n", argv[0]);
     }
     return status;
 }
@@ -344,7 +344,7 @@ int add_monitor_command(int argc, char** argv, GString* output) {
         tag = find_unused_tag();
         if (!tag) {
             g_string_append_printf(output,
-                "%s: there are not enough free tags!\n", argv[0]);
+                "%s: There are not enough free tags\n", argv[0]);
             return HERBST_TAG_IN_USE;
         }
     }
@@ -352,13 +352,13 @@ int add_monitor_command(int argc, char** argv, GString* output) {
         tag = find_tag(argv[2]);
         if (!tag) {
             g_string_append_printf(output,
-                "%s: The tag \"%s\" does not exist!\n", argv[0], argv[2]);
+                "%s: The tag \"%s\" does not exist\n", argv[0], argv[2]);
             return HERBST_INVALID_ARGUMENT;
         }
     }
     if (find_monitor_with_tag(tag)) {
         g_string_append_printf(output,
-            "%s: The tag \"%s\" is already viewed on a monitor!\n", argv[0], argv[2]);
+            "%s: The tag \"%s\" is already viewed on a monitor\n", argv[0], argv[2]);
         return HERBST_TAG_IN_USE;
     }
     HSMonitor* monitor = add_monitor(rect, tag);
@@ -422,13 +422,13 @@ int move_monitor_command(int argc, char** argv, GString* output) {
     int index = atoi(argv[1]);
     if (index < 0 || index >= g_monitors->len) {
         g_string_append_printf(output,
-            "%s: index %i is out of range!\n", argv[0], index);
+            "%s: Index %i is out of range\n", argv[0], index);
         return HERBST_INVALID_ARGUMENT;
     }
     XRectangle rect = parse_rectangle(argv[2]);
     if (rect.width < WINDOW_MIN_WIDTH || rect.height < WINDOW_MIN_HEIGHT) {
         g_string_append_printf(output,
-            "%s: rectangle is too small!\n", argv[0]);
+            "%s: Rectangle is too small\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     // else: just move it:
@@ -459,7 +459,7 @@ int monitor_rect_command(int argc, char** argv, GString* output) {
             with_pad = true;
         } else {
             g_string_append_printf(output,
-                "%s: invalid argument \"%s\"\n", argv[0], argv[1]);
+                "%s: Invalid argument \"%s\"\n", argv[0], argv[1]);
             return HERBST_INVALID_ARGUMENT;
         }
     }
@@ -470,7 +470,7 @@ int monitor_rect_command(int argc, char** argv, GString* output) {
             m = monitor_with_index(index);
             if (!m) {
                 g_string_append_printf(output,
-                    "%s: invalid index \"%s\"\n", argv[0], index_str);
+                    "%s: Invalid index \"%s\"\n", argv[0], index_str);
                 return HERBST_INVALID_ARGUMENT;
             }
         }
@@ -498,7 +498,7 @@ int monitor_set_pad_command(int argc, char** argv, GString* output) {
     int index = atoi(argv[1]);
     if (index < 0 || index >= g_monitors->len) {
         g_string_append_printf(output,
-            "%s: index %i is out of range!\n", argv[0], index);
+            "%s: Index %i is out of range\n", argv[0], index);
         return HERBST_INVALID_ARGUMENT;
     }
     HSMonitor* monitor = monitor_with_index(index);
@@ -644,7 +644,7 @@ int monitor_set_tag_command(int argc, char** argv, GString* output) {
         return 0;
     } else {
         g_string_append_printf(output,
-            "%s: Invalid monitor or tag!\n", argv[0]);
+            "%s: Invalid monitor or tag\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
 }
@@ -660,7 +660,7 @@ int monitor_set_tag_by_index_command(int argc, char** argv, GString* output) {
     HSTag* tag = get_tag_by_index_str(argv[1], skip_visible);
     if (!tag) {
         g_string_append_printf(output,
-            "%s: Invalid index \"%s\"!\n", argv[0], argv[1]);
+            "%s: Invalid index \"%s\"\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     monitor_set_tag(get_current_monitor(), tag);
@@ -841,7 +841,7 @@ int monitor_lock_tag_command(int argc, char** argv, GString* output) {
     }
     if (!monitor) {
         g_string_append_printf(output,
-            "%s: Invalid monitor!\n", argv[0]);
+            "%s: Invalid monitor\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     monitor->lock_tag = true;
@@ -858,7 +858,7 @@ int monitor_unlock_tag_command(int argc, char** argv, GString* output) {
     }
     if (!monitor) {
         g_string_append_printf(output,
-            "%s: Invalid monitor!\n", argv[0]);
+            "%s: Invalid monitor\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     monitor->lock_tag = false;
@@ -949,7 +949,7 @@ int detect_monitors_command(int argc, char **argv, GString* output) {
     g_free(monitors);
     if (ret == HERBST_TAG_IN_USE && output != NULL) {
         g_string_append_printf(output,
-            "%s: there are not enough free tags!\n", argv[0]);
+            "%s: There are not enough free tags\n", argv[0]);
     }
     return ret;
 }
@@ -976,7 +976,7 @@ int monitor_raise_command(int argc, char** argv, GString* output) {
     }
     if (!monitor) {
         g_string_append_printf(output,
-            "%s: Invalid monitor!\n", argv[0]);
+            "%s: Invalid monitor\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     stack_raise_slide(g_monitor_stack, monitor->slice);
diff --git a/src/mouse.c b/src/mouse.c
index dac1c9e..b2da143 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -163,7 +163,7 @@ int mouse_bind_command(int argc, char** argv, GString* output) {
     char* string = argv[1];
     if (!string2modifiers(string, &modifiers)) {
         g_string_append_printf(output,
-            "%s: Modifier \"%s\" does not exist!\n", argv[0], string);
+            "%s: Modifier \"%s\" does not exist\n", argv[0], string);
         return HERBST_INVALID_ARGUMENT;
     }
     // last one is the mouse button
@@ -171,13 +171,13 @@ int mouse_bind_command(int argc, char** argv, GString* output) {
     unsigned int button = string2button(last_token);
     if (button == 0) {
         g_string_append_printf(output,
-            "%s: Unknown mouse button \"%s\"!\n", argv[0], last_token);
+            "%s: Unknown mouse button \"%s\"\n", argv[0], last_token);
         return HERBST_INVALID_ARGUMENT;
     }
     MouseFunction function = string2mousefunction(argv[2]);
     if (!function) {
         g_string_append_printf(output,
-            "%s: Unknown mouse action \"%s\"!\n", argv[0], argv[2]);
+            "%s: Unknown mouse action \"%s\"\n", argv[0], argv[2]);
         return HERBST_INVALID_ARGUMENT;
     }
     mouse_bind_function(modifiers, button, function);
diff --git a/src/rules.c b/src/rules.c
index ecacb79..831f91f 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -118,7 +118,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
     HSCondition cond;
     if (op != '=' && type == g_maxage_type) {
         g_string_append_printf(output,
-            "condition maxage only supports the = operator\n");
+            "rule: Condition maxage only supports the = operator\n");
         return NULL;
     }
     switch (op) {
@@ -127,7 +127,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
                 cond.value_type = CONDITION_VALUE_TYPE_INTEGER;
                 if (1 != sscanf(value, "%d", &cond.value.integer)) {
                     g_string_append_printf(output,
-                        "cannot integer from \"%s\"\n", value);
+                        "rule: Can not integer from \"%s\"\n", value);
                     return NULL;
                 }
             } else {
@@ -143,7 +143,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
                 char buf[ERROR_STRING_BUF_SIZE];
                 regerror(status, &cond.value.exp, buf, ERROR_STRING_BUF_SIZE);
                 g_string_append_printf(output,
-                    "Cannot parse value \"%s\" from condition \"%s\": \"%s\"\n",
+                    "rule: Can not parse value \"%s\" from condition \"%s\": \"%s\"\n",
                     value, g_condition_types[type].name, buf);
                 return NULL;
             }
@@ -151,7 +151,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
 
         default:
             g_string_append_printf(output,
-                "unknown rule condition operation \"%c\"\n", op);
+                "rule: Unknown rule condition operation \"%c\"\n", op);
             return NULL;
             break;
     }
@@ -206,7 +206,7 @@ HSConsequence* consequence_create(int type, char op, char* value, GString* outpu
 
         default:
             g_string_append_printf(output,
-                "unknown rule consequence operation \"%c\"\n", op);
+                "rule: Unknown rule consequence operation \"%c\"\n", op);
             return NULL;
             break;
     }
@@ -300,7 +300,7 @@ int rule_add_command(int argc, char** argv, GString* output) {
     // temporary data structures
     HSRule* rule = rule_create();
     HSCondition* cond;
-    HSConsequence*  cons;
+    HSConsequence* cons;
     bool negated = false;
     struct {
         char* name;
@@ -357,7 +357,7 @@ int rule_add_command(int argc, char** argv, GString* output) {
         else {
             // need to hardcode "rule:" here because args are shifted
             g_string_append_printf(output,
-                "rule: unknown argument \"%s\"\n", *argv);
+                "rule: Unknown argument \"%s\"\n", *argv);
             return HERBST_INVALID_ARGUMENT;
         }
     }
@@ -382,7 +382,7 @@ int rule_remove_command(int argc, char** argv, GString* output) {
     }
 
     g_string_append_printf(output,
-        "%s: this command must be used with --all/-F for the time being\n", argv[0]);
+        "%s: This command must be used with --all/-F\n", argv[0]);
     return HERBST_INVALID_ARGUMENT;
 }
 
diff --git a/src/settings.c b/src/settings.c
index fd0e5d2..e79afab 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -122,7 +122,7 @@ int settings_set_command(int argc, char** argv, GString* output) {
     if (!pair) {
         if (output != NULL) {
             g_string_append_printf(output,
-                "%s: setting \"%s\" not found!\n", argv[0], argv[1]);
+                "%s: Setting \"%s\" not found\n", argv[0], argv[1]);
         }
         return HERBST_SETTING_NOT_FOUND;
     }
@@ -164,7 +164,7 @@ int settings_get(int argc, char** argv, GString* output) {
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
         g_string_append_printf(output,
-            "%s: setting \"%s\" not found!\n", argv[0], argv[1]);
+            "%s: Setting \"%s\" not found\n", argv[0], argv[1]);
         return HERBST_SETTING_NOT_FOUND;
     }
     if (pair->type == HS_Int) {
@@ -183,7 +183,7 @@ int settings_toggle(int argc, char** argv, GString* output) {
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
         g_string_append_printf(output,
-            "%s: setting \"%s\" not found!\n", argv[0], argv[1]);
+            "%s: Setting \"%s\" not found\n", argv[0], argv[1]);
         return HERBST_SETTING_NOT_FOUND;
     }
     if (pair->type == HS_Int) {
@@ -222,7 +222,7 @@ int settings_cycle_value(int argc, char** argv, GString* output) {
     SettingsPair* pair = settings_find(argv[1]);
     if (!pair) {
         g_string_append_printf(output,
-            "%s: setting \"%s\" not found!", argv[0], argv[1]);
+            "%s: Setting \"%s\" not found\n", argv[0], argv[1]);
         return HERBST_SETTING_NOT_FOUND;
     }
     (void)SHIFT(argc, argv);
diff --git a/src/tag.c b/src/tag.c
index c7524a2..18d4e0d 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -161,12 +161,12 @@ int tag_rename_command(int argc, char** argv, GString* output) {
     HSTag* tag = find_tag(argv[1]);
     if (!tag) {
         g_string_append_printf(output,
-            "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
+            "%s: Tag \"%s\" not found\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     if (find_tag(argv[2])) {
         g_string_append_printf(output,
-            "%s: Tag \"%s\" already exists!\n", argv[0], argv[2]);
+            "%s: Tag \"%s\" already exists\n", argv[0], argv[2]);
         return HERBST_TAG_IN_USE;
     }
     g_string_assign(tag->name, argv[2]);
@@ -186,21 +186,21 @@ int tag_remove_command(int argc, char** argv, GString* output) {
     HSTag* target = (argc >= 3) ? find_tag(argv[2]) : get_current_monitor()->tag;
     if (!tag) {
         g_string_append_printf(output,
-            "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
+            "%s: Tag \"%s\" not found\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     } else if (!target) {
         g_string_append_printf(output,
-            "%s: Tag \"%s\" not found!\n", argv[0], argv[2]);
+            "%s: Tag \"%s\" not found\n", argv[0], argv[2]);
     } else if (tag == target) {
         g_string_append_printf(output,
-            "%s: Cannot merge tag \"%s\" into itself!\n", argv[0], argv[1]);
+            "%s: Cannot merge tag \"%s\" into itself\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     HSMonitor* monitor = find_monitor_with_tag(tag);
     HSMonitor* monitor_target = find_monitor_with_tag(target);
     if (monitor) {
         g_string_append_printf(output,
-            "%s: Cannot merge the currently viewed tag!\n", argv[0]);
+            "%s: Cannot merge the currently viewed tag\n", argv[0]);
         return HERBST_TAG_IN_USE;
     }
     // save all these windows
@@ -251,7 +251,7 @@ int tag_set_floating_command(int argc, char** argv, GString* output) {
         action = argv[2];
         if (!tag) {
             g_string_append_printf(output,
-                "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
+                "%s: Tag \"%s\" not found\n", argv[0], argv[1]);
             return HERBST_INVALID_ARGUMENT;
         }
     }
@@ -336,7 +336,7 @@ int tag_move_window_command(int argc, char** argv, GString* output) {
     HSTag* target = find_tag(argv[1]);
     if (!target) {
         g_string_append_printf(output,
-            "%s: Tag \"%s\" not found!\n", argv[0], argv[1]);
+            "%s: Tag \"%s\" not found\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
     tag_move_focused_client(target);
-- 
1.8.0

From 01c210daa1502610c10c4ff39f23ed09db9ac612 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 21:30:17 +0100
Subject: [PATCH 13/25] Add an error message if "raise" can't find client

---
 src/main.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/main.c b/src/main.c
index 5b27526..b8e9ed8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -55,7 +55,7 @@ int print_layout_command(int argc, char** argv, GString* output);
 int load_command(int argc, char** argv, GString* output);
 int print_tag_status_command(int argc, char** argv, GString* output);
 void execute_autostart_file();
-int raise_command(int argc, char** argv);
+int raise_command(int argc, char** argv, GString* output);
 int spawn(int argc, char** argv);
 int wmexec(int argc, char** argv);
 static void remove_zombies(int signal);
@@ -137,7 +137,7 @@ CommandBinding g_commands[] = {
     CMD_BIND(             "move_monitor",   move_monitor_command),
     CMD_BIND(             "monitor_rect",   monitor_rect_command),
     CMD_BIND(             "pad",            monitor_set_pad_command),
-    CMD_BIND_NO_OUTPUT(   "raise",          raise_command),
+    CMD_BIND(             "raise",          raise_command),
     CMD_BIND(             "rule",           rule_add_command),
     CMD_BIND(             "unrule",         rule_remove_command),
     CMD_BIND(             "layout",         print_layout_command),
@@ -345,7 +345,7 @@ int wmexec(int argc, char** argv) {
     return EXIT_SUCCESS;
 }
 
-int raise_command(int argc, char** argv) {
+int raise_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
@@ -354,6 +354,14 @@ int raise_command(int argc, char** argv) {
     win = string_to_client(argv[1], &client);
     if (client) {
         client_raise(client);
+    } else if (win == 0) {
+        g_string_append_printf(output,
+            "%s: Could not find client", argv[0]);
+        if (argc > 1) {
+            g_string_append_printf(output, " \"%s\".\n", argv[1]);
+        } else {
+            g_string_append(output, ".\n");
+        }
     } else {
         XRaiseWindow(g_display, win);
     }
-- 
1.8.0

From 11ad15af5889b36cd64076c4117e15f3a7d45e3b Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 21:42:24 +0100
Subject: [PATCH 14/25] Add error messages for remove_monitor

---
 src/main.c    |  2 +-
 src/monitor.c | 12 ++++++++++--
 src/monitor.h |  2 +-
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/main.c b/src/main.c
index b8e9ed8..0373380 100644
--- a/src/main.c
+++ b/src/main.c
@@ -133,7 +133,7 @@ CommandBinding g_commands[] = {
     CMD_BIND(             "move_index",     tag_move_window_by_index_command),
     CMD_BIND(             "add_monitor",    add_monitor_command),
     CMD_BIND(             "raise_monitor",  monitor_raise_command),
-    CMD_BIND_NO_OUTPUT(   "remove_monitor", remove_monitor_command),
+    CMD_BIND(             "remove_monitor", remove_monitor_command),
     CMD_BIND(             "move_monitor",   move_monitor_command),
     CMD_BIND(             "monitor_rect",   monitor_rect_command),
     CMD_BIND(             "pad",            monitor_set_pad_command),
diff --git a/src/monitor.c b/src/monitor.c
index b641a3d..51e4208 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -372,13 +372,21 @@ int add_monitor_command(int argc, char** argv, GString* output) {
     return 0;
 }
 
-int remove_monitor_command(int argc, char** argv) {
+int remove_monitor_command(int argc, char** argv, GString* output) {
     // usage: remove_monitor INDEX
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
     int index = atoi(argv[1]);
-    return remove_monitor(index);
+    int ret = remove_monitor(index);
+    if (ret == HERBST_INVALID_ARGUMENT) {
+        g_string_append_printf(output,
+            "%s: Index needs to be between 0 and %d\n", argv[0], g_monitors->len - 1);
+    } else if (ret == HERBST_FORBIDDEN) {
+        g_string_append_printf(output,
+            "%s: Can't remove the last monitor\n", argv[0]);
+    }
+    return ret;
 }
 
 int remove_monitor(int index) {
diff --git a/src/monitor.h b/src/monitor.h
index 212d9f9..6f268e8 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -57,7 +57,7 @@ int monitor_cycle_command(int argc, char** argv);
 int monitor_focus_command(int argc, char** argv);
 int add_monitor_command(int argc, char** argv, GString* output);
 int monitor_raise_command(int argc, char** argv, GString* output);
-int remove_monitor_command(int argc, char** argv);
+int remove_monitor_command(int argc, char** argv, GString* output);
 int remove_monitor(int index);
 int list_monitors(int argc, char** argv, GString* output);
 int list_padding(int argc, char** argv, GString* output);
-- 
1.8.0

From 091271825d84850e14805c01512be25a6b478e34 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 21:42:57 +0100
Subject: [PATCH 15/25] Add error message for set_monitors

---
 src/monitor.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/monitor.c b/src/monitor.c
index 51e4208..c560ff2 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -286,6 +286,9 @@ int set_monitor_rects_command(int argc, char** argv, GString* output) {
     if (status == HERBST_TAG_IN_USE) {
         g_string_append_printf(output,
             "%s: There are not enough free tags\n", argv[0]);
+    } else if (status == HERBST_INVALID_ARGUMENT) {
+        g_string_append_printf(output,
+            "%s: Need at least one rectangle\n", argv[0]);
     }
     return status;
 }
-- 
1.8.0

From 062dd40390219c96f837fac53abc695784409d8d Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 21:43:27 +0100
Subject: [PATCH 16/25] Add error message for toggle for non-ints

---
 src/settings.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/settings.c b/src/settings.c
index e79afab..a62e94d 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -197,6 +197,8 @@ int settings_toggle(int argc, char** argv, GString* output) {
         }
     } else {
         // only toggle numbers
+        g_string_append_printf(output,
+            "%s: Only numbers can be toggled\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     // on successful change, call callback
-- 
1.8.0

From d0b89e551e07a0efed4050c768b875ef19c056c3 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 21:52:26 +0100
Subject: [PATCH 17/25] Add error message when setting a wrong type

---
 src/settings.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/src/settings.c b/src/settings.c
index a62e94d..648c764 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -126,7 +126,12 @@ int settings_set_command(int argc, char** argv, GString* output) {
         }
         return HERBST_SETTING_NOT_FOUND;
     }
-    return settings_set(pair, argv[2]);
+    int ret = settings_set(pair, argv[2]);
+    if (ret == HERBST_INVALID_ARGUMENT) {
+        g_string_append_printf(output,
+            "%s: Invalid value for setting \"%s\"\n", argv[0], argv[1]);
+    }
+    return ret;
 }
 
 int settings_set(SettingsPair* pair, char* value) {
@@ -232,6 +237,11 @@ int settings_cycle_value(int argc, char** argv, GString* output) {
     char** pcurrent = table_find(argv, sizeof(*argv), argc, 0,
                                  memberequals_settingspair, pair);
     int i = pcurrent ? ((INDEX_OF(argv, pcurrent) + 1) % argc) : 0;
-    return settings_set(pair, argv[i]);
+    int ret = settings_set(pair, argv[i]);
+    if (ret == HERBST_INVALID_ARGUMENT) {
+        g_string_append_printf(output,
+            "%s: Invalid value for setting \"%s\"\n", argv[0], argv[1]);
+    }
+    return ret;
 }
 
-- 
1.8.0

From 6e1ffc469dcbb1ceebbd69fb874a25df68ec666f Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 22:49:49 +0100
Subject: [PATCH 18/25] prepend "load: " to msgs in load_command

---
 src/layout.c | 12 ++++++------
 src/main.c   |  3 +++
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/layout.c b/src/layout.c
index dced9d3..ec7de7d 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -345,7 +345,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         if (3 != sscanf(args, "%[^"SEP"]"SEP"%lf"SEP"%d",
             align_name, &fraction_double, &selection)) {
             g_string_append_printf(errormsg,
-                "load: Can not parse frame args \"%s\"\n", args);
+                "Can not parse frame args \"%s\"\n", args);
             return NULL;
         }
 #undef SEP
@@ -353,7 +353,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         g_free(align_name);
         if (align < 0) {
             g_string_append_printf(errormsg,
-                "load: Invalid align name in args \"%s\"\n", args);
+                "Invalid align name in args \"%s\"\n", args);
             return NULL;
         }
         selection = !!selection; // CLAMP it to [0;1]
@@ -368,7 +368,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
             frame_split(frame, align, fraction);
             if (frame->type != TYPE_FRAMES) {
                 g_string_append_printf(errormsg,
-                    "load: Can not split frame\n");
+                    "Can not split frame\n");
                 return NULL;
             }
         }
@@ -389,7 +389,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         if (2 != sscanf(args, "%[^"SEP"]"SEP"%d",
             layout_name, &selection)) {
             g_string_append_printf(errormsg,
-                "load: Can not parse frame args \"%s\"\n", args);
+                "Can not parse frame args \"%s\"\n", args);
             return NULL;
         }
 #undef SEP
@@ -397,7 +397,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         g_free(layout_name);
         if (layout < 0) {
             g_string_append_printf(errormsg,
-                "load: Can not parse layout from args \"%s\"\n", args);
+                "Can not parse layout from args \"%s\"\n", args);
             return NULL;
         }
 
@@ -434,7 +434,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
             Window win;
             if (1 != sscanf(description, "0x%lx\n", &win)) {
                 g_string_append_printf(errormsg,
-                    "load: Can not parse window id from \"%s\"\n", description);
+                    "Can not parse window id from \"%s\"\n", description);
                 return NULL;
             }
             // jump over window id and over whitespaces
diff --git a/src/main.c b/src/main.c
index 0373380..76b99f0 100644
--- a/src/main.c
+++ b/src/main.c
@@ -224,6 +224,9 @@ int load_command(int argc, char** argv, GString* output) {
     }
     assert(tag != NULL);
     char* rest = load_frame_tree(tag->frame, layout_string, output);
+    if (output->len > 0) {
+        g_string_prepend(output, "load: ");
+    }
     tag_set_flags_dirty(); // we probably changed some window positions
     // arrange monitor
     HSMonitor* m = find_monitor_with_tag(tag);
-- 
1.8.0

From 53a3c1e9036944961e8eb376435f191303a3d681 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 22:51:36 +0100
Subject: [PATCH 19/25] Avoid shifting in monitor commands

---
 src/monitor.c | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/src/monitor.c b/src/monitor.c
index c560ff2..d5bfea5 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -273,15 +273,14 @@ int disjoin_rects_command(int argc, char** argv, GString* output) {
 }
 
 int set_monitor_rects_command(int argc, char** argv, GString* output) {
-    (void)SHIFT(argc, argv);
-    if (argc < 1) {
+    if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
-    XRectangle* templates = g_new0(XRectangle, argc);
-    for (int i = 0; i < argc; i++) {
+    XRectangle* templates = g_new0(XRectangle, argc - 1);
+    for (int i = 1; i < (argc - 1); i++) {
         templates[i] = parse_rectangle(argv[i]);
     }
-    int status = set_monitor_rects(templates, argc);
+    int status = set_monitor_rects(templates, argc - 1);
     g_free(templates);
     if (status == HERBST_TAG_IN_USE) {
         g_string_append_printf(output,
@@ -843,10 +842,9 @@ void monitors_lock_changed() {
 }
 
 int monitor_lock_tag_command(int argc, char** argv, GString* output) {
-    (void)SHIFT(argc, argv);
     HSMonitor *monitor;
-    if (argc >= 1) {
-        monitor = monitor_with_index(atoi(argv[0]));
+    if (argc >= 2) {
+        monitor = monitor_with_index(atoi(argv[1]));
     } else {
         monitor = get_current_monitor();
     }
@@ -860,10 +858,9 @@ int monitor_lock_tag_command(int argc, char** argv, GString* output) {
 }
 
 int monitor_unlock_tag_command(int argc, char** argv, GString* output) {
-    (void)SHIFT(argc, argv);
     HSMonitor *monitor;
-    if (argc >= 1) {
-        monitor = monitor_with_index(atoi(argv[0]));
+    if (argc >= 2) {
+        monitor = monitor_with_index(atoi(argv[1]));
     } else {
         monitor = get_current_monitor();
     }
@@ -978,10 +975,9 @@ HSStack* get_monitor_stack() {
 }
 
 int monitor_raise_command(int argc, char** argv, GString* output) {
-    (void)SHIFT(argc, argv);
     HSMonitor* monitor;
-    if (argc >= 1) {
-        monitor = monitor_with_index(atoi(argv[0]));
+    if (argc >= 2) {
+        monitor = monitor_with_index(atoi(argv[1]));
     } else {
         monitor = get_current_monitor();
     }
-- 
1.8.0

From 26c7b5b97afd41c0411a46c25714b31238a16ed2 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 22:52:16 +0100
Subject: [PATCH 20/25] rule: handle function name for error msgs better

---
 src/rules.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/src/rules.c b/src/rules.c
index 831f91f..f4b830b 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -118,7 +118,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
     HSCondition cond;
     if (op != '=' && type == g_maxage_type) {
         g_string_append_printf(output,
-            "rule: Condition maxage only supports the = operator\n");
+            "Condition maxage only supports the = operator\n");
         return NULL;
     }
     switch (op) {
@@ -127,7 +127,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
                 cond.value_type = CONDITION_VALUE_TYPE_INTEGER;
                 if (1 != sscanf(value, "%d", &cond.value.integer)) {
                     g_string_append_printf(output,
-                        "rule: Can not integer from \"%s\"\n", value);
+                        "Can not integer from \"%s\"\n", value);
                     return NULL;
                 }
             } else {
@@ -143,7 +143,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
                 char buf[ERROR_STRING_BUF_SIZE];
                 regerror(status, &cond.value.exp, buf, ERROR_STRING_BUF_SIZE);
                 g_string_append_printf(output,
-                    "rule: Can not parse value \"%s\" from condition \"%s\": \"%s\"\n",
+                    "Can not parse value \"%s\" from condition \"%s\": \"%s\"\n",
                     value, g_condition_types[type].name, buf);
                 return NULL;
             }
@@ -151,7 +151,7 @@ HSCondition* condition_create(int type, char op, char* value, GString* output) {
 
         default:
             g_string_append_printf(output,
-                "rule: Unknown rule condition operation \"%c\"\n", op);
+                "Unknown rule condition operation \"%c\"\n", op);
             return NULL;
             break;
     }
@@ -206,7 +206,7 @@ HSConsequence* consequence_create(int type, char op, char* value, GString* outpu
 
         default:
             g_string_append_printf(output,
-                "rule: Unknown rule consequence operation \"%c\"\n", op);
+                "Unknown rule consequence operation \"%c\"\n", op);
             return NULL;
             break;
     }
@@ -297,6 +297,7 @@ int rule_add_command(int argc, char** argv, GString* output) {
     if (argc < 2) {
         return HERBST_NEED_MORE_ARGS;
     }
+    char* cmd_name = argv[0]; // save this before shifting
     // temporary data structures
     HSRule* rule = rule_create();
     HSCondition* cond;
@@ -336,6 +337,12 @@ int rule_add_command(int argc, char** argv, GString* output) {
 
         else if (consorcond && (type = find_condition_type(name)) >= 0) {
             cond = condition_create(type, op, value, output);
+            if (output->len > 0) { // if there was output
+                // Equivalent to this, but there is no g_string_prepend_printf:
+                // g_string_prepend_printf(output, "%s: ", cmd_name);
+                g_string_prepend(output, ": ");
+                g_string_prepend(output, cmd_name);
+            }
             if (!cond) {
                 rule_destroy(rule);
                 return HERBST_INVALID_ARGUMENT;
@@ -347,6 +354,12 @@ int rule_add_command(int argc, char** argv, GString* output) {
 
         else if (consorcond && (type = find_consequence_type(name)) >= 0) {
             cons = consequence_create(type, op, value, output);
+            if (output->len > 0) { // if there was output
+                // Equivalent to this, but there is no g_string_prepend_printf:
+                // g_string_prepend_printf(output, "%s: ", cmd_name);
+                g_string_prepend(output, ": ");
+                g_string_prepend(output, cmd_name);
+            }
             if (!cons) {
                 rule_destroy(rule);
                 return HERBST_INVALID_ARGUMENT;
@@ -355,16 +368,12 @@ int rule_add_command(int argc, char** argv, GString* output) {
         }
 
         else {
-            // need to hardcode "rule:" here because args are shifted
             g_string_append_printf(output,
-                "rule: Unknown argument \"%s\"\n", *argv);
+                "Unknown argument \"%s\"\n", *argv);
             return HERBST_INVALID_ARGUMENT;
         }
     }
 
-    if (output->len > 0) { // if there was output
-        g_string_prepend(output, "rule: ");
-    }
     g_queue_push_tail(&g_rules, rule);
     return 0;
 }
-- 
1.8.0

From 29d38c53b53010f7bd8fde72a4ec980dfc9a68ba Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 22:54:19 +0100
Subject: [PATCH 21/25] Handle argv-shifting correctly in settings

---
 src/settings.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/settings.c b/src/settings.c
index 648c764..2318131 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -223,6 +223,8 @@ bool memberequals_settingspair(void* pmember, void* needle) {
 }
 
 int settings_cycle_value(int argc, char** argv, GString* output) {
+    char* cmd_name = argv[0];
+    char* setting_name = argv[1]; // save this before shifting
     if (argc < 3) {
         return HERBST_NEED_MORE_ARGS;
     }
@@ -240,7 +242,7 @@ int settings_cycle_value(int argc, char** argv, GString* output) {
     int ret = settings_set(pair, argv[i]);
     if (ret == HERBST_INVALID_ARGUMENT) {
         g_string_append_printf(output,
-            "%s: Invalid value for setting \"%s\"\n", argv[0], argv[1]);
+            "%s: Invalid value for setting \"%s\"\n", cmd_name, setting_name);
     }
     return ret;
 }
-- 
1.8.0

From 4bd3b810ff986d4cd35180240a0db22f33163edc Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Thu, 15 Nov 2012 23:10:34 +0100
Subject: [PATCH 22/25] Add error message if tag can't be switched

---
 src/monitor.c | 27 ++++++++++++++++++---------
 src/monitor.h |  2 +-
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/src/monitor.c b/src/monitor.c
index d5bfea5..7b30758 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -573,11 +573,11 @@ void all_monitors_apply_layout() {
     }
 }
 
-void monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
+int monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
     HSMonitor* other = find_monitor_with_tag(tag);
     if (monitor == other) {
         // nothing to do
-        return;
+        return 0;
     }
     if (monitor->lock_tag) {
         // If the monitor tag is locked, do not change the tag
@@ -586,7 +586,7 @@ void monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
             // displaying monitor
             monitor_focus_by_index(monitor_index_of(other));
         }
-        return;
+        return 1;
     }
     if (other != NULL) {
         if (*g_swap_monitors_to_get_tag) {
@@ -594,7 +594,7 @@ void monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
                 // the monitor we want to steal the tag from is
                 // locked. focus that monitor instead
                 monitor_focus_by_index(monitor_index_of(other));
-                return;
+                return 1;
             }
             // swap tags
             other->tag = monitor->tag;
@@ -614,7 +614,7 @@ void monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
             emit_tag_changed(other->tag, monitor_index_of(other));
             emit_tag_changed(tag, g_cur_monitor);
         }
-        return;
+        return 0;
     }
     HSTag* old_tag = monitor->tag;
     // 1. show new tag
@@ -641,6 +641,7 @@ void monitor_set_tag(HSMonitor* monitor, HSTag* tag) {
     while (XCheckMaskEvent(g_display, EnterWindowMask, &ev));
     ewmh_update_current_desktop();
     emit_tag_changed(tag, g_cur_monitor);
+    return 0;
 }
 
 int monitor_set_tag_command(int argc, char** argv, GString* output) {
@@ -650,8 +651,12 @@ int monitor_set_tag_command(int argc, char** argv, GString* output) {
     HSMonitor* monitor = get_current_monitor();
     HSTag*  tag = find_tag(argv[1]);
     if (monitor && tag) {
-        monitor_set_tag(monitor, tag);
-        return 0;
+        int ret = monitor_set_tag(monitor, tag);
+        if (ret != 0) {
+            g_string_append_printf(output,
+                "%s: Could not change tag (maybe monitor is locked?)\n", argv[0]);
+        }
+        return ret;
     } else {
         g_string_append_printf(output,
             "%s: Invalid monitor or tag\n", argv[0]);
@@ -673,8 +678,12 @@ int monitor_set_tag_by_index_command(int argc, char** argv, GString* output) {
             "%s: Invalid index \"%s\"\n", argv[0], argv[1]);
         return HERBST_INVALID_ARGUMENT;
     }
-    monitor_set_tag(get_current_monitor(), tag);
-    return 0;
+    int ret = monitor_set_tag(get_current_monitor(), tag);
+    if (ret != 0) {
+        g_string_append_printf(output,
+            "%s: Could not change tag (maybe monitor is locked?)\n", argv[0]);
+    }
+    return ret;
 }
 
 int monitor_focus_command(int argc, char** argv) {
diff --git a/src/monitor.h b/src/monitor.h
index 6f268e8..a23adca 100644
--- a/src/monitor.h
+++ b/src/monitor.h
@@ -68,7 +68,7 @@ int move_monitor_command(int argc, char** argv, GString* output);
 int monitor_rect_command(int argc, char** argv, GString* output);
 HSMonitor* get_current_monitor();
 int monitor_count();
-void monitor_set_tag(HSMonitor* monitor, struct HSTag* tag);
+int monitor_set_tag(HSMonitor* monitor, struct HSTag* tag);
 int monitor_set_pad_command(int argc, char** argv, GString* output);
 int monitor_set_tag_command(int argc, char** argv, GString* output);
 int monitor_set_tag_by_index_command(int argc, char** argv, GString* output);
-- 
1.8.0

From 7fd3bfc4c15efd73179a546998939138ea981a34 Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Sat, 17 Nov 2012 23:06:51 +0100
Subject: [PATCH 23/25] dump: More / clearer error messages

---
 src/layout.c | 6 ++++--
 src/main.c   | 2 +-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/layout.c b/src/layout.c
index ec7de7d..f2a5672 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -302,7 +302,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
     // find next (
     description = strchr(description, LAYOUT_DUMP_BRACKETS[0]);
     if (!description) {
-        g_string_append_printf(errormsg, "missing %c\n",
+        g_string_append_printf(errormsg, "Missing %c\n",
             LAYOUT_DUMP_BRACKETS[0]);
         return NULL;
     }
@@ -328,10 +328,12 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
     // jump over args substring
     description += args_len;
     if (!*description) {
+        g_string_append_printf(errormsg, "Missing %c or arguments\n", LAYOUT_DUMP_BRACKETS[1]);
         return NULL;
     }
     description += strspn(description, LAYOUT_DUMP_WHITESPACES);
     if (!*description) {
+        g_string_append_printf(errormsg, "Missing %c or arguments\n", LAYOUT_DUMP_BRACKETS[1]);
         return NULL;
     }
 
@@ -353,7 +355,7 @@ char* load_frame_tree(HSFrame* frame, char* description, GString* errormsg) {
         g_free(align_name);
         if (align < 0) {
             g_string_append_printf(errormsg,
-                "Invalid align name in args \"%s\"\n", args);
+                "Invalid alignment name in args \"%s\"\n", args);
             return NULL;
         }
         selection = !!selection; // CLAMP it to [0;1]
diff --git a/src/main.c b/src/main.c
index 76b99f0..2995395 100644
--- a/src/main.c
+++ b/src/main.c
@@ -241,7 +241,7 @@ int load_command(int argc, char** argv, GString* output) {
     }
     if (!rest) {
         g_string_append_printf(output,
-            "%s: Layout \"%s\" unknown\n", argv[0], layout_string);
+            "%s: Error while parsing!\n", argv[0]);
         return HERBST_INVALID_ARGUMENT;
     }
     if (rest[0] != '\0') { // if string was not parsed completely
-- 
1.8.0

From 3e2ca29b313a65a7526f2755dcbbd39bbb214bee Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Sat, 17 Nov 2012 23:20:58 +0100
Subject: [PATCH 24/25] tag_status: CLAMP correctly

---
 src/main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main.c b/src/main.c
index 2995395..552358d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -259,7 +259,7 @@ int print_tag_status_command(int argc, char** argv, GString* output) {
     if (argc >= 2) {
         monitor_index = atoi(argv[1]);
     }
-    monitor_index = CLAMP(monitor_index, 0, monitor_count());
+    monitor_index = CLAMP(monitor_index, 0, monitor_count() - 1);
     tag_update_flags();
     HSMonitor* monitor = monitor_with_index(monitor_index);
     g_string_append_c(output, '\t');
-- 
1.8.0

From 670aa00903e6fc1a0c3b7838d781a360182ac3dd Mon Sep 17 00:00:00 2001
From: Florian Bruhin <git _at_ the _minus_ compiler _dot_ org>
Date: Sun, 18 Nov 2012 00:36:31 +0100
Subject: [PATCH 25/25] Update MIGRATION

---
 MIGRATION | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/MIGRATION b/MIGRATION
index 5406512..5cf7b4d 100644
--- a/MIGRATION
+++ b/MIGRATION
@@ -4,6 +4,12 @@ herbstluftwm migration guide
 This guide describes the list of incompatible changes between the different
 herbstluftwm releases and how to migrate scripts and configuration.
 
+0.4 to 0.5
+~~~~~~~~~~
+herbstclient now returns the exitstatus 9 (HERBST_NEED_MORE_ARGS) instead of 3
+(HERBST_INVALID_ARGUMENT) when a command needs more arguments. When an error
+occurs, it now outputs an error message to stderr.
+
 0.3 to 0.4
 ~~~~~~~~~~
 The setting window_gap is now called frame_gap. Simply replace all occurrences
-- 
1.8.0

Attachment: pgp8_4qP0RMXO.pgp
Description: PGP signature