--- freem/src/fma_gedit.c	2025/03/09 19:14:24	1.3
+++ freem/src/fma_gedit.c	2025/03/31 16:33:56	1.5
@@ -1,5 +1,5 @@
 /*
- *   $Id: fma_gedit.c,v 1.3 2025/03/09 19:14:24 snw Exp $
+ *   $Id: fma_gedit.c,v 1.5 2025/03/31 16:33:56 snw Exp $
  *    FreeM global editor
  *
  *  
@@ -24,6 +24,12 @@
  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
  *
  *   $Log: fma_gedit.c,v $
+ *   Revision 1.5  2025/03/31 16:33:56  snw
+ *   Work on fmadm edit global
+ *
+ *   Revision 1.4  2025/03/30 01:36:58  snw
+ *   Make it easier to bring back fma_gedit, fix double-free in global handler, limit $CHAR to 7-bit ASCII
+ *
  *   Revision 1.3  2025/03/09 19:14:24  snw
  *   First phase of REUSE compliance and header reformat
  *
@@ -46,19 +52,33 @@
 #include "fmadm.h"
 #include "fma_globals.h"
 
-#if defined HAVE_NCURSESW_CURSES_H
-#  include <ncursesw/curses.h>
-#elif defined HAVE_NCURSESW_H
-#  include <ncursesw.h>
-#elif defined HAVE_NCURSES_CURSES_H
-#  include <ncurses/curses.h>
-#elif defined HAVE_NCURSES_H
-#  include <ncurses.h>
-#elif defined HAVE_CURSES_H
-#  include <curses.h>
-#else
-#  error "SysV or X/Open-compatible Curses header file required"
-#endif
+#ifdef HAVE_LIBREADLINE
+#  if defined(HAVE_READLINE_READLINE_H)
+#    include <readline/readline.h>
+#  elif defined(HAVE_READLINE_H)
+#    include <readline.h>
+#  else /* !defined(HAVE_READLINE_H) */
+extern char *readline ();
+#  endif /* !defined(HAVE_READLINE_H) */
+/*char *cmdline = NULL;*/
+#else /* !defined(HAVE_READLINE_READLINE_H) */
+  /* no readline */
+#endif /* HAVE_LIBREADLINE */
+
+#ifdef HAVE_READLINE_HISTORY
+#  if defined(HAVE_READLINE_HISTORY_H)
+#    include <readline/history.h>
+#  elif defined(HAVE_HISTORY_H)
+#    include <history.h>
+#  else /* !defined(HAVE_HISTORY_H) */
+extern void add_history ();
+extern int write_history ();
+extern int read_history ();
+#  endif /* defined(HAVE_READLINE_HISTORY_H) */
+  /* no history */
+#endif /* HAVE_READLINE_HISTORY */
+
+
 
 #define GE_MXGBL 100
 
@@ -121,22 +141,6 @@ int ge_nextbuf;
 int ge_rows;
 int ge_columns;
 
-WINDOW *wge_key;
-WINDOW *wge_key_border;
-WINDOW *wge_node;
-WINDOW *wge_node_border;
-WINDOW *wge_msg_border;
-WINDOW *wge_msg;
-WINDOW *wge_block_border;
-WINDOW *wge_block;
-WINDOW *wge_global_border;
-WINDOW *wge_global;
-WINDOW *wge_command;
-
-WINDOW *wge_cur;
-
-void ge_set_wintitle(WINDOW *border_window, char *title);
-void ge_wininit(void);
 void ge_update_gbl(void);
 void ge_select_buffer(int buf);
 short ge_select_block(int buf, long blocknum);
@@ -145,135 +149,141 @@ int ge_open_global(char *gblname);
 void ge_init_buffers(void);
 void ge_eventloop(void);
 void ge_decode_key(const char *key, char *buf);
-void ge_win_next(void);
-void ge_win_previous(void);
+void ge_describe_block(void);
 
 #define SPC ' '
 
+
+void ge_describe_gbl(void)
+{
+    printf ("global %s [#%d]\n", ge_buffers[ge_curbuf].name, ge_curbuf);
+    printf ("namespace %s\n", ge_buffers[ge_curbuf].namespace);
+    printf ("block size %d bytes\n", BLOCKLEN);
+    printf ("block count %d\n", ge_buffers[ge_curbuf].blockct);
+    printf ("file size %d bytes\n", ge_buffers[ge_curbuf].gblsize);
+}
+
+void ge_update_gbl(void)
+{
+    printf ("fmadm:  selected global %s into buffer %d\n", ge_buffers[ge_curbuf].name, ge_curbuf);
+}
+   
+
 int fma_globals_edit(int optc, char **opts)
 {
+    #define MODE_GBL 0
+    #define MODE_BLK 1
+#if defined(HAVE_LIBREADLINE) && !defined(_AIX)
     int editbuf;        
+    char fmge_prompt[256];
+    char *cmdt = (char *) malloc (65535 * sizeof (char));
+    char *fmarl_buf;
+    char **args;
+    int mode = MODE_GBL;
+    char *result = (char *) malloc (65535 * sizeof (char));;
+    int argc;
+    int tmpres;
+    register int i;
+
+    /* first dimension */
+    if ((args = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {	
+        fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
+        return 1;
+    } 
+
+    /* second dimension */
+    for (i = 0; i < FMA_MAXARGS; i++) {
+        if ((args[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
+            fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
+            return 1;
+        } 
+    }
+
     
     ge_curbuf = 0;
     ge_nextbuf = 0;
-
-    ge_init_buffers ();
-    initscr ();
-    ge_wininit ();
-
-    wge_cur = wge_command;
-    
-    wprintw (wge_msg, "FreeM Global Editor\n");
-    wprintw (wge_msg, " Copyright (C) 2023 Coherent Logic Development LLC\n\n");
-
-    wattron (wge_msg, A_BOLD);
-    wprintw (wge_msg, "Left and right arrow keys navigate blocks; 'q' to quit.\n\n");
-    wattroff (wge_msg, A_BOLD);
-    wrefresh (wge_msg);
+    ge_init_buffers ();   
     
     if (optc == 2) {
         
         if ((editbuf = ge_open_global (opts[fma_base_opt])) == -1) {
-            wprintw (wge_msg, "fmadm:  cannot open global %s\n", opts[fma_base_opt]);
+            fprintf (stderr, "fmadm:  cannot open global %s\n", opts[fma_base_opt]);
         }
         else {        
             ge_select_buffer (editbuf);
         }
         
     }
-    
-    ge_eventloop ();
-    
-    endwin ();
-    return 0;
-}
-
-void ge_win_next(void)
-{
 
-    /*
-    switch (wge_cur) {
-
-        case wge_key:
-            wge_cur = wge_node;
-            break;
-
-        case wge_node:
-            wge_cur = wge_global;
-            break;
-
-        case wge_global:
-            wge_cur = wge_block;
-            break;
-
-        case wge_block:
-            wge_cur = wge_command;
-            break;
-
-        case wge_command:
-            wge_cur = wge_msg;
-            break;
-
-        case wge_msg:
-            wge_cur = wge_key;
-            break;
-
-    }
-    */
-
-}
-    
-
-void ge_win_previous(void)
-{
-
-}
-    
+    while(1) {
+        if (mode == MODE_GBL) {
+            sprintf (fmge_prompt, "global edit %s [buf %d/%d]> ",
+                     ge_buffers[ge_curbuf].name,
+                     ge_curbuf,
+                     GE_MXGBL);
+        }
+        else {
+            sprintf (fmge_prompt, "block edit %s [blk %d/%d]> ",
+                     ge_buffers[ge_curbuf].name,
+                     ge_buffers[ge_curbuf].blocknum,
+                     ge_buffers[ge_curbuf].blockct);
+        }
+        
+        fmarl_buf = readline (fmge_prompt);
+        if (fmarl_buf == (char *) NULL) continue;
 
-void ge_eventloop(void)
-{
-    int c;
-    short quit_flag;
+        cmdt = strtok (fmarl_buf, " ");
+        if (cmdt == (char *) NULL) continue;
 
-    quit_flag = FALSE;
+        i = 0;
+        while ((result = strtok (NULL, " ")) != NULL) {        
+            strcpy (args[i++], result);
+        }
 
-    while (!quit_flag) {
+        argc = i;
+        
+        for (i = 0; i < strlen (cmdt); i++) cmdt[i] = cmdt[i] | 0140;
 
-        noecho ();
-        c = wgetch (wge_command);
-        echo ();
-
-        switch (c) {
-
-            case 'q':
-            case 'Q':
-                quit_flag = TRUE;
-                break;
-
-            case KEY_LEFT:
-                if (ge_buffers[ge_curbuf].blocknum != 0) {
-                    ge_select_block (ge_curbuf, ge_buffers[ge_curbuf].blocknum - 1);
-                }
-                else {
-                    ge_select_block (ge_curbuf, ge_buffers[ge_curbuf].blockct - 1);
-                }
-                break;
-
-            case KEY_RIGHT:
-                if (ge_buffers[ge_curbuf].blocknum + 1 < ge_buffers[ge_curbuf].blockct) {
-                    ge_select_block (ge_curbuf, ge_buffers[ge_curbuf].blocknum + 1);
-                }
-                else {
-                    ge_select_block (ge_curbuf, 0);
-                }
-                break;
-                
+        if (strcmp (cmdt, "exit") == 0 || strcmp (cmdt, "quit") == 0) {
+            return 0;
         }
-
+        else if (strcmp (cmdt, "block") == 0) {
+            mode = MODE_BLK;
+        }
+        else if (strcmp (cmdt, "global") == 0) {
+            mode = MODE_GBL;
+        }
+        else if (strcmp (cmdt, "describe") == 0) {
+            if (mode == MODE_GBL) {
+                ge_describe_gbl ();
+            }
+            else {
+                ge_describe_block ();
+            }
+        }
+        else if (strcmp (cmdt, "open") == 0) {
+            if (mode == MODE_GBL) {
+                printf ("TODO\n");
+            }
+            else {
+                long blknum;
+                blknum = atoi (args[0]);
+                ge_select_block (ge_curbuf, blknum);
+            }
+        }
+        else {
+            printf ("fmadm:  command %s not recognized\n", cmdt);
+        }
+        
+        
     }
+#endif    
+        
 
+    return 0;
 }
 
+
 void ge_init_buffers(void)
 {
     register int i;
@@ -296,87 +306,12 @@ void ge_init_buffers(void)
     }
 }
 
-void ge_wininit(void)
-{
-    int half;
-    
-    getmaxyx (stdscr, ge_rows, ge_columns);
-
-    half = ge_rows / 2;    
-
-    /* messages window */
-    wge_msg_border = newwin (10, ge_columns - 41, ge_rows - 12, 0);
-    wge_msg = newwin (8, ge_columns - 43, ge_rows - 11, 1);
-    ge_set_wintitle (wge_msg_border, "Messages");
-    wrefresh (wge_msg_border);
-    wrefresh (wge_msg);
-
-    /* global window */
-    wge_global_border = newwin (half, 40, 0, ge_columns - 40);
-    wge_global = newwin (half - 2, 38, 1, ge_columns - 39);
-    ge_set_wintitle (wge_global_border, "No Global Selected");
-    wrefresh (wge_global_border);
-
-    /* block window */
-    wge_block_border = newwin (half - 1, 40, half, ge_columns - 40);
-    wge_block = newwin (half - 3, 37, half + 1, ge_columns - 38); 
-    ge_set_wintitle (wge_block_border, "Block");
-    wrefresh (wge_block_border);
-    
-    /* command window */
-    wge_command = newwin (1, ge_columns, ge_rows - 1, 0);
-    wrefresh (wge_command);
-
-    scrollok (wge_msg, TRUE);
-    keypad (wge_command, TRUE);
-    keypad (wge_msg, TRUE);
-    keypad (wge_global, TRUE);
-    keypad (wge_block, TRUE);
-
-    curs_set (0);
-}
-
-void ge_update_gbl(void)
-{
-    char wintit[4096];
-    
-    wclear (wge_global);
-    snprintf (wintit, 4095, "%s [#%d]", ge_buffers[ge_curbuf].name, ge_curbuf);
-    ge_set_wintitle (wge_global_border, wintit);
-
-    wattron (wge_global, A_BOLD);
-    wprintw (wge_global, "GLOBAL:      ");
-    wattroff (wge_global, A_BOLD);
-    wprintw (wge_global, "%s\n", ge_buffers[ge_curbuf].name);
-    
-    wattron (wge_global, A_BOLD);
-    wprintw (wge_global, "NAMESPACE:   ");
-    wattroff (wge_global, A_BOLD);
-    wprintw (wge_global, "%s\n", ge_buffers[ge_curbuf].namespace);
-
-    wattron (wge_global, A_BOLD);
-    wprintw (wge_global, "BLOCK SIZE:  ");
-    wattroff (wge_global, A_BOLD);
-    wprintw (wge_global, "%d bytes\n", BLOCKLEN);
-
-    wattron (wge_global, A_BOLD);
-    wprintw (wge_global, "BLOCK COUNT: ");
-    wattroff (wge_global, A_BOLD);
-    wprintw (wge_global, "%d\n", ge_buffers[ge_curbuf].blockct);
-
-    wattron (wge_global, A_BOLD);
-    wprintw (wge_global, "FILE SIZE:   ");
-    wattroff (wge_global, A_BOLD);
-    wprintw (wge_global, "%d bytes\n", ge_buffers[ge_curbuf].gblsize);
 
-    wrefresh (wge_global);
-}
     
 
 void ge_select_buffer(int buf)
 {        
-    wprintw (wge_msg, "Selected buffer %d\n", buf);
-    wrefresh (wge_msg);
+    printf ("fmadm:  selected buffer %d\n", buf);
 
     ge_curbuf = buf;
 
@@ -387,15 +322,15 @@ short ge_select_block(int buf, long bloc
 {
     ge_blockinfo *b;
     char *br;
-    char key[256];
-    char decoded[4096];
+    char key[2056];
+    char decoded[64096];
     long i;
     long j;
     long k;
     long length;
     
     if ((blocknum < 0) || (blocknum > (ge_buffers[buf].blockct - 1))) {
-        wprintw (wge_msg, "Block number for global %s must be between 0 and %d\n", ge_buffers[buf].name, ge_buffers[buf].blockct - 1);
+        printf ("block number for global %s must be between 0 and %d\n", ge_buffers[buf].name, ge_buffers[buf].blockct - 1);
         return FALSE;
     }
 
@@ -468,8 +403,8 @@ short ge_select_block(int buf, long bloc
         key[k] = g_EOL;
 
         ge_decode_key (key, decoded);
-        decoded[stlen (decoded)] = '\0';
-        wprintw (wge_msg, "found key %s\n", decoded);
+
+        printf ("found key %s\n", decoded);
         
         b->keyct++;
     }
@@ -548,48 +483,27 @@ void ge_decode_key(const char *key, char
     
 }
 
-void ge_update_block(void)
+void ge_describe_block(void)
 {
-    char wintit[4096];
-
-    wclear (wge_block);
-    snprintf (wintit, 4095, "Block %d of %d", ge_buffers[ge_curbuf].blocknum, ge_buffers[ge_curbuf].blockct);
-    ge_set_wintitle (wge_block_border, wintit);
-
-    wattron (wge_block, A_BOLD);
-    wprintw (wge_block, "TYPE:               ");
-    wattroff (wge_block, A_BOLD);
-    wprintw (wge_block, "%s\n", ge_buffers[ge_curbuf].block.bt_desc);
+    printf ("type = %s\n", ge_buffers[ge_curbuf].block.bt_desc);
 
     if (ge_buffers[ge_curbuf].blocknum != ROOT) {
-        wattron (wge_block, A_BOLD);
-        wprintw (wge_block, "LEFT LINK POINTER:  ");
-        wattroff (wge_block, A_BOLD);
-        wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.llptr);
-        
-        wattron (wge_block, A_BOLD);
-        wprintw (wge_block, "RIGHT LINK POINTER: ");
-        wattroff (wge_block, A_BOLD);
-        wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.rlptr);
+        printf ("llptr = %d\n", ge_buffers[ge_curbuf].block.llptr);        
+        printf ("rlptr = %d\n", ge_buffers[ge_curbuf].block.rlptr);
     }
     else {
-        wattron (wge_block, A_BOLD);
-        wprintw (wge_block, "BLOCK COUNT:        ");
-        wattroff (wge_block, A_BOLD);
-        wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.blockcount);
-        
-        wattron (wge_block, A_BOLD);
-        wprintw (wge_block, "FREE OFFSET:        ");
-        wattroff (wge_block, A_BOLD);
-        wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.free_offset);
-    }
-
-    wattron (wge_block, A_BOLD);
-    wprintw (wge_block, "KEY COUNT:          ");
-    wattroff (wge_block, A_BOLD);
-    wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.keyct);
-    
-    wrefresh (wge_block);
+        printf ("block count = %d\n", ge_buffers[ge_curbuf].block.blockcount);
+        printf ("offset to free space = %d\n", ge_buffers[ge_curbuf].block.free_offset);
+    }
+
+    printf ("key count = %d\n", ge_buffers[ge_curbuf].block.keyct);
+}
+
+void ge_update_block(void)
+{
+
+    printf ("fmadm:  selected block %d of %d\n", ge_buffers[ge_curbuf].blocknum, ge_buffers[ge_curbuf].blockct);
+
 }
 
 int ge_open_global(char *gblname)
@@ -602,18 +516,14 @@ int ge_open_global(char *gblname)
     
     snprintf (gpath, 4095, "%s/%s", fma_global_path, gblname);
 
-    wprintw (wge_msg, "Opening global %s [path %s, namespace %s]... ", gblname, gpath, fma_namespace);
+    printf ("fmadm:  opening global %s [path %s, namespace %s]... ", gblname, gpath, fma_namespace);
 
-    wrefresh (wge_msg);
-    
     if ((ge_buffers[buf].fd = open (gpath, 0)) == -1) {
-        wprintw (wge_msg, "[FAIL]\n");
-        wrefresh (wge_msg);
+        printf ("[FAIL]\n");
         return -1;
     }
     else {
-        wprintw (wge_msg, "[OK]\n");
-        wrefresh (wge_msg);
+        printf ("[OK]\n");
     }
 
     fstat (ge_buffers[buf].fd, &sb);
@@ -635,11 +545,3 @@ int ge_open_global(char *gblname)
     return buf;
 }
 
-void ge_set_wintitle(WINDOW *border_window, char *title)
-{
-    box (border_window, 0, 0);
-    wattron (border_window, A_BOLD);
-    mvwprintw (border_window, 0, 3, title);
-    wattroff (border_window, A_BOLD);
-    wrefresh (border_window);
-}