ctdb/docs: Include ceph rados namespace support in man page
[samba.git] / source3 / utils / regedit_hexedit.c
index 69ed622c7ea871fe4a8c65c259e325068ae4c37d..413e563f653f1abb197999b125d7173ef82471bb 100644 (file)
@@ -1,30 +1,64 @@
+/*
+ * Samba Unix/Linux SMB client library
+ * Registry Editor
+ * Copyright (C) Christopher Davis 2012
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include "includes.h"
 #include "regedit_hexedit.h"
 
+/*
+ offset    hex1         hex2         ascii
+ 00000000  FF FF FF FF  FF FF FF FF  ........
+*/
+
+#define HEX_COL1 10
+#define HEX_COL1_END 21
+#define HEX_COL2 23
+#define HEX_COL2_END 34
+#define ASCII_COL 36
+#define ASCII_COL_END LINE_WIDTH
+#define BYTES_PER_LINE 8
+
+struct hexedit {
+       size_t offset;
+       size_t len;
+       size_t alloc_size;
+       int cursor_y;
+       int cursor_x;
+       size_t cursor_offset;
+       size_t cursor_line_offset;
+       int nibble;
+       uint8_t *data;
+       WINDOW *win;
+};
+
 static int max_rows(WINDOW *win)
 {
-       int maxy, maxx;
+       int maxy;
 
-       getmaxyx(win, maxy, maxx);
+       maxy = getmaxy(win);
 
        return maxy - 1;
 }
 
-static int hexedit_free(struct hexedit *buf)
-{
-       if (buf->status_line) {
-               delwin(buf->status_line);
-       }
-       if (buf->win) {
-               delwin(buf->win);
-       }
-
-       return 0;
-}
-
-struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines,
-                           int y, int x, size_t sz)
+struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, const void *data,
+                           size_t sz)
 {
+       WERROR rv;
        struct hexedit *buf;
 
        buf = talloc_zero(ctx, struct hexedit);
@@ -32,33 +66,53 @@ struct hexedit *hexedit_new(TALLOC_CTX *ctx, WINDOW *parent, int nlines,
                return NULL;
        }
 
-       talloc_set_destructor(buf, hexedit_free);
+       buf->win = parent;
+
+       rv = hexedit_set_buf(buf, data, sz);
+       if (!W_ERROR_IS_OK(rv)) {
+               goto fail;
+       }
+
+       return buf;
+
+fail:
+       talloc_free(buf);
+
+       return NULL;
+}
+
+WERROR hexedit_set_buf(struct hexedit *buf, const void *data, size_t sz)
+{
+       TALLOC_FREE(buf->data);
 
        buf->data = talloc_zero_array(buf, uint8_t, sz);
        if (buf->data == NULL) {
-               goto fail;
+               return WERR_NOT_ENOUGH_MEMORY;
+       }
+
+       if (data != NULL) {
+               memcpy(buf->data, data, sz);
        }
 
        buf->len = sz;
        buf->alloc_size = sz;
-       buf->win = derwin(parent, nlines, LINE_WIDTH, y, x);
-       if (buf->win == NULL) {
-               goto fail;
-       }
        buf->cursor_x = HEX_COL1;
+       buf->cursor_y = 0;
+       buf->cursor_offset = 0;
+       buf->cursor_line_offset = 0;
+       buf->nibble = 0;
 
-       buf->status_line = derwin(buf->win, 1, LINE_WIDTH, max_rows(buf->win), 0);
-       if (buf->status_line == NULL) {
-               goto fail;
-       }
-       wattron(buf->status_line, A_REVERSE | A_STANDOUT);
-
-       return buf;
+       return WERR_OK;
+}
 
-fail:
-       talloc_free(buf);
+const void *hexedit_get_buf(struct hexedit *buf)
+{
+       return buf->data;
+}
 
-       return NULL;
+size_t hexedit_get_buf_len(struct hexedit *buf)
+{
+       return buf->len;
 }
 
 static size_t bytes_per_screen(WINDOW *win)
@@ -68,11 +122,21 @@ static size_t bytes_per_screen(WINDOW *win)
 
 void hexedit_set_cursor(struct hexedit *buf)
 {
-       werase(buf->status_line);
-       wprintw(buf->status_line, "Len:%lu Off:%lu Val:0x%X", buf->len,
-               buf->cursor_offset, buf->data[buf->cursor_offset]);
-       wrefresh(buf->status_line);
+       wmove(buf->win, max_rows(buf->win), 0);
+       wattron(buf->win, A_REVERSE | A_STANDOUT);
+       wclrtoeol(buf->win);
+       if (buf->cursor_offset < buf->len) {
+               wprintw(buf->win, "Len:%lu Off:%lu Val:0x%X", buf->len,
+                       buf->cursor_offset, buf->data[buf->cursor_offset]);
+       } else {
+               wprintw(buf->win, "Len:%lu Off:%lu", buf->len,
+                       buf->cursor_offset);
+       }
+       wattroff(buf->win, A_REVERSE | A_STANDOUT);
        wmove(buf->win, buf->cursor_y, buf->cursor_x);
+       wcursyncup(buf->win);
+       wsyncup(buf->win);
+       untouchwin(buf->win);
 }
 
 void hexedit_refresh(struct hexedit *buf)
@@ -82,18 +146,24 @@ void hexedit_refresh(struct hexedit *buf)
        size_t off;
 
        werase(buf->win);
+       if (buf->len == 0) {
+               mvwprintw(buf->win, 0, 0, "%08X", 0);
+               return;
+       }
 
        end = buf->offset + bytes_per_screen(buf->win);
        if (end > buf->len) {
                end = buf->len;
        }
 
-       for (off = buf->offset, lineno = 0; off < end; off += BYTES_PER_LINE, ++lineno) {
+       for (off = buf->offset, lineno = 0;
+            off < end;
+            off += BYTES_PER_LINE, ++lineno) {
                uint8_t *line = buf->data + off;
                size_t i, endline;
 
                wmove(buf->win, lineno, 0);
-               wprintw(buf->win, "%08X  ", off);
+               wprintw(buf->win, "%08zX  ", off);
 
                endline = BYTES_PER_LINE;
 
@@ -125,7 +195,8 @@ void hexedit_refresh(struct hexedit *buf)
 
 static void calc_cursor_offset(struct hexedit *buf)
 {
-       buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE + buf->cursor_line_offset;
+       buf->cursor_offset = buf->offset + buf->cursor_y * BYTES_PER_LINE +
+                               buf->cursor_line_offset;
 }
 
 static int offset_to_hex_col(size_t pos)
@@ -153,17 +224,6 @@ static int offset_to_hex_col(size_t pos)
        return -1;
 }
 
-static bool scroll_down(struct hexedit *buf)
-{
-       if (buf->offset + bytes_per_screen(buf->win) >= buf->len) {
-               return false;
-       }
-
-       buf->offset += BYTES_PER_LINE;
-
-       return true;
-}
-
 static bool scroll_up(struct hexedit *buf)
 {
        if (buf->offset == 0) {
@@ -177,17 +237,34 @@ static bool scroll_up(struct hexedit *buf)
 
 static void cursor_down(struct hexedit *buf)
 {
+       size_t space;
+       bool need_refresh = false;
+
+       space = buf->offset + (buf->cursor_y + 1) * BYTES_PER_LINE;
+       if (space > buf->len) {
+               return;
+       }
+
        if (buf->cursor_y + 1 == max_rows(buf->win)) {
-               if (scroll_down(buf)) {
-                       hexedit_refresh(buf);
-               }
+               buf->offset += BYTES_PER_LINE;
+               need_refresh = true;
        } else {
-               if (buf->cursor_offset + BYTES_PER_LINE >= buf->len) {
-                       return;
-               }
                buf->cursor_y++;
        }
 
+       if (buf->cursor_offset + BYTES_PER_LINE > buf->len) {
+               buf->nibble = 0;
+               buf->cursor_offset = buf->len;
+               buf->cursor_line_offset = buf->len - space;
+               if (buf->cursor_x >= ASCII_COL) {
+                       buf->cursor_x = ASCII_COL + buf->cursor_line_offset;
+               } else {
+                       buf->cursor_x = offset_to_hex_col(buf->cursor_line_offset);
+               }
+       }
+       if (need_refresh) {
+               hexedit_refresh(buf);
+       }
        calc_cursor_offset(buf);
 }
 
@@ -238,7 +315,7 @@ static void cursor_left(struct hexedit *buf)
        } else if (buf->cursor_x == ASCII_COL) {
                size_t off = buf->offset + buf->cursor_y * BYTES_PER_LINE;
                if (off + 7 >= buf->len) {
-                       size_t lastpos = buf->len - off - 1;
+                       size_t lastpos = buf->len - off;
                        buf->cursor_x = offset_to_hex_col(lastpos) + 1;
                        buf->cursor_line_offset = lastpos;
                } else {
@@ -269,7 +346,7 @@ static void cursor_right(struct hexedit *buf)
                return;
        }
        if ((buf->cursor_x >= ASCII_COL || buf->nibble == 1) &&
-           buf->cursor_offset + 1 == buf->len) {
+           buf->cursor_offset == buf->len) {
                if (buf->cursor_x < ASCII_COL) {
                        new_x = ASCII_COL;
                        buf->cursor_line_offset = 0;
@@ -306,6 +383,10 @@ static void do_edit(struct hexedit *buf, int c)
 {
        uint8_t *byte;
 
+       if (buf->cursor_offset == buf->len) {
+               hexedit_resize_buffer(buf, buf->len + 1);
+       }
+
        byte = buf->data + buf->cursor_offset;
 
        if (buf->cursor_x >= ASCII_COL) {
@@ -316,8 +397,13 @@ static void do_edit(struct hexedit *buf, int c)
                if (!isprint(c)) {
                        c = '.';
                }
-               mvwaddch(buf->win, buf->cursor_y, ASCII_COL + buf->cursor_line_offset, c);
-               cursor_right(buf);
+               mvwaddch(buf->win, buf->cursor_y,
+                        ASCII_COL + buf->cursor_line_offset, c);
+               if (buf->cursor_x + 1 != ASCII_COL_END) {
+                       cursor_right(buf);
+               } else {
+                       cursor_down(buf);
+               }
        } else {
                if (!isxdigit(c)) {
                        return;
@@ -340,12 +426,71 @@ static void do_edit(struct hexedit *buf, int c)
                if (!isprint(c)) {
                        c = '.';
                }
-               mvwaddch(buf->win, buf->cursor_y, ASCII_COL + buf->cursor_line_offset, c);
+               mvwaddch(buf->win, buf->cursor_y,
+                        ASCII_COL + buf->cursor_line_offset, c);
 
                if (buf->cursor_x + 1 != HEX_COL2_END) {
                        cursor_right(buf);
+               } else {
+                       cursor_down(buf);
                }
        }
+
+       hexedit_refresh(buf);
+}
+
+static void erase_at(struct hexedit *buf, size_t pos)
+{
+       if (pos >= buf->len) {
+               return;
+       }
+
+       if (pos < buf->len - 1) {
+               /* squeeze the character out of the buffer */
+               uint8_t *p = buf->data + pos;
+               uint8_t *end = buf->data + buf->len;
+               memmove(p, p + 1, end - p - 1);
+       }
+
+       buf->len--;
+       hexedit_refresh(buf);
+}
+
+static void do_backspace(struct hexedit *buf)
+{
+       size_t off;
+       bool do_erase = true;
+
+       if (buf->cursor_offset == 0) {
+               return;
+       }
+
+       off = buf->cursor_offset;
+       if (buf->cursor_x == ASCII_COL) {
+               cursor_up(buf);
+               buf->cursor_line_offset = 7;
+               buf->cursor_x = ASCII_COL_END - 1;
+               calc_cursor_offset(buf);
+       } else if (buf->cursor_x == HEX_COL1) {
+               cursor_up(buf);
+               buf->cursor_line_offset = 7;
+               buf->cursor_x = HEX_COL2_END - 1;
+               buf->nibble = 1;
+               calc_cursor_offset(buf);
+       } else {
+               if (buf->cursor_x < ASCII_COL && buf->nibble) {
+                       do_erase = false;
+               }
+               cursor_left(buf);
+       }
+       if (do_erase) {
+               erase_at(buf, off - 1);
+       }
+}
+
+static void do_delete(struct hexedit *buf)
+{
+       erase_at(buf, buf->cursor_offset);
 }
 
 void hexedit_driver(struct hexedit *buf, int c)
@@ -367,17 +512,25 @@ void hexedit_driver(struct hexedit *buf, int c)
                break;
        case HE_CURSOR_PGDN:
                break;
+       case HE_BACKSPACE:
+               do_backspace(buf);
+               break;
+       case HE_DELETE:
+               do_delete(buf);
+               break;
        default:
                do_edit(buf, c & 0xff);
                break;
        }
+
+       hexedit_set_cursor(buf);
 }
 
 WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz)
 {
        /* reset the cursor if it'll be out of bounds
           after the resize */
-       if (buf->cursor_offset >= newsz) {
+       if (buf->cursor_offset > newsz) {
                buf->cursor_y = 0;
                buf->cursor_x = HEX_COL1;
                buf->offset = 0;
@@ -389,12 +542,16 @@ WERROR hexedit_resize_buffer(struct hexedit *buf, size_t newsz)
        if (newsz > buf->len) {
                if (newsz > buf->alloc_size) {
                        uint8_t *d;
-                       d = talloc_realloc(buf, buf->data, uint8_t, newsz);
+                       buf->alloc_size *= 2;
+                       if (newsz > buf->alloc_size) {
+                               buf->alloc_size = newsz;
+                       }
+                       d = talloc_realloc(buf, buf->data, uint8_t,
+                                          buf->alloc_size);
                        if (d == NULL) {
-                               return WERR_NOMEM;
+                               return WERR_NOT_ENOUGH_MEMORY;
                        }
                        buf->data = d;
-                       buf->alloc_size = newsz;
                }
                memset(buf->data + buf->len, '\0', newsz - buf->len);
                buf->len = newsz;