|
|
| version 1.1.1.1, 2025/01/19 02:04:04 | version 1.5, 2025/03/31 16:33:56 |
|---|---|
| Line 1 | Line 1 |
| /* | /* |
| * * | * $Id$ |
| * * * | |
| * * * | |
| * *************** | |
| * * * * * | |
| * * MUMPS * | |
| * * * * * | |
| * *************** | |
| * * * | |
| * * * | |
| * * | |
| * | |
| * fma_gedit.c | |
| * FreeM global editor | * FreeM global editor |
| * | * |
| * | * |
| * Author: Serena Willis <jpw@coherent-logic.com> | * Author: Serena Willis <snw@coherent-logic.com> |
| * Copyright (C) 1998 MUG Deutschland | * Copyright (C) 1998 MUG Deutschland |
| * Copyright (C) 2023 Coherent Logic Development LLC | * Copyright (C) 2023, 2025 Coherent Logic Development LLC |
| * | * |
| * | * |
| * This file is part of FreeM. | * This file is part of FreeM. |
| Line 35 | Line 23 |
| * You should have received a copy of the GNU Affero Public License | * You should have received a copy of the GNU Affero Public License |
| * along with FreeM. If not, see <https://www.gnu.org/licenses/>. | * along with FreeM. If not, see <https://www.gnu.org/licenses/>. |
| * | * |
| * $Log$ | |
| * 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 | |
| * | |
| * | |
| * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC | |
| * SPDX-License-Identifier: AGPL-3.0-or-later | |
| **/ | **/ |
| #include <stdlib.h> | #include <stdlib.h> |
| Line 51 | Line 52 |
| #include "fmadm.h" | #include "fmadm.h" |
| #include "fma_globals.h" | #include "fma_globals.h" |
| #if defined HAVE_NCURSESW_CURSES_H | #ifdef HAVE_LIBREADLINE |
| # include <ncursesw/curses.h> | # if defined(HAVE_READLINE_READLINE_H) |
| #elif defined HAVE_NCURSESW_H | # include <readline/readline.h> |
| # include <ncursesw.h> | # elif defined(HAVE_READLINE_H) |
| #elif defined HAVE_NCURSES_CURSES_H | # include <readline.h> |
| # include <ncurses/curses.h> | # else /* !defined(HAVE_READLINE_H) */ |
| #elif defined HAVE_NCURSES_H | extern char *readline (); |
| # include <ncurses.h> | # endif /* !defined(HAVE_READLINE_H) */ |
| #elif defined HAVE_CURSES_H | /*char *cmdline = NULL;*/ |
| # include <curses.h> | #else /* !defined(HAVE_READLINE_READLINE_H) */ |
| #else | /* no readline */ |
| # error "SysV or X/Open-compatible Curses header file required" | #endif /* HAVE_LIBREADLINE */ |
| #endif | |
| #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 | #define GE_MXGBL 100 |
| Line 126 int ge_nextbuf; | Line 141 int ge_nextbuf; |
| int ge_rows; | int ge_rows; |
| int ge_columns; | 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_update_gbl(void); |
| void ge_select_buffer(int buf); | void ge_select_buffer(int buf); |
| short ge_select_block(int buf, long blocknum); | short ge_select_block(int buf, long blocknum); |
| Line 150 int ge_open_global(char *gblname); | Line 149 int ge_open_global(char *gblname); |
| void ge_init_buffers(void); | void ge_init_buffers(void); |
| void ge_eventloop(void); | void ge_eventloop(void); |
| void ge_decode_key(const char *key, char *buf); | void ge_decode_key(const char *key, char *buf); |
| void ge_win_next(void); | void ge_describe_block(void); |
| void ge_win_previous(void); | |
| #define SPC ' ' | #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) | int fma_globals_edit(int optc, char **opts) |
| { | { |
| #define MODE_GBL 0 | |
| #define MODE_BLK 1 | |
| #if defined(HAVE_LIBREADLINE) && !defined(_AIX) | |
| int editbuf; | 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_curbuf = 0; |
| ge_nextbuf = 0; | ge_nextbuf = 0; |
| ge_init_buffers (); | |
| 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); | |
| if (optc == 2) { | if (optc == 2) { |
| if ((editbuf = ge_open_global (opts[fma_base_opt])) == -1) { | 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 { | else { |
| ge_select_buffer (editbuf); | 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) | cmdt = strtok (fmarl_buf, " "); |
| { | if (cmdt == (char *) NULL) continue; |
| int c; | |
| short quit_flag; | |
| 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 (); | if (strcmp (cmdt, "exit") == 0 || strcmp (cmdt, "quit") == 0) { |
| c = wgetch (wge_command); | return 0; |
| 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; | |
| } | } |
| 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) | void ge_init_buffers(void) |
| { | { |
| register int i; | register int i; |
| Line 301 void ge_init_buffers(void) | Line 306 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) | void ge_select_buffer(int buf) |
| { | { |
| wprintw (wge_msg, "Selected buffer %d\n", buf); | printf ("fmadm: selected buffer %d\n", buf); |
| wrefresh (wge_msg); | |
| ge_curbuf = buf; | ge_curbuf = buf; |
| Line 392 short ge_select_block(int buf, long bloc | Line 322 short ge_select_block(int buf, long bloc |
| { | { |
| ge_blockinfo *b; | ge_blockinfo *b; |
| char *br; | char *br; |
| char key[256]; | char key[2056]; |
| char decoded[4096]; | char decoded[64096]; |
| long i; | long i; |
| long j; | long j; |
| long k; | long k; |
| long length; | long length; |
| if ((blocknum < 0) || (blocknum > (ge_buffers[buf].blockct - 1))) { | 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; | return FALSE; |
| } | } |
| Line 473 short ge_select_block(int buf, long bloc | Line 403 short ge_select_block(int buf, long bloc |
| key[k] = g_EOL; | key[k] = g_EOL; |
| ge_decode_key (key, decoded); | 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++; | b->keyct++; |
| } | } |
| Line 553 void ge_decode_key(const char *key, char | Line 483 void ge_decode_key(const char *key, char |
| } | } |
| void ge_update_block(void) | void ge_describe_block(void) |
| { | { |
| char wintit[4096]; | printf ("type = %s\n", ge_buffers[ge_curbuf].block.bt_desc); |
| 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); | |
| if (ge_buffers[ge_curbuf].blocknum != ROOT) { | if (ge_buffers[ge_curbuf].blocknum != ROOT) { |
| wattron (wge_block, A_BOLD); | printf ("llptr = %d\n", ge_buffers[ge_curbuf].block.llptr); |
| wprintw (wge_block, "LEFT LINK POINTER: "); | printf ("rlptr = %d\n", ge_buffers[ge_curbuf].block.rlptr); |
| 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); | |
| } | } |
| else { | else { |
| wattron (wge_block, A_BOLD); | printf ("block count = %d\n", ge_buffers[ge_curbuf].block.blockcount); |
| wprintw (wge_block, "BLOCK COUNT: "); | printf ("offset to free space = %d\n", ge_buffers[ge_curbuf].block.free_offset); |
| wattroff (wge_block, A_BOLD); | } |
| wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.blockcount); | |
| printf ("key count = %d\n", ge_buffers[ge_curbuf].block.keyct); | |
| wattron (wge_block, A_BOLD); | } |
| wprintw (wge_block, "FREE OFFSET: "); | |
| wattroff (wge_block, A_BOLD); | void ge_update_block(void) |
| wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.free_offset); | { |
| } | |
| printf ("fmadm: selected block %d of %d\n", ge_buffers[ge_curbuf].blocknum, ge_buffers[ge_curbuf].blockct); | |
| 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); | |
| } | } |
| int ge_open_global(char *gblname) | int ge_open_global(char *gblname) |
| Line 607 int ge_open_global(char *gblname) | Line 516 int ge_open_global(char *gblname) |
| snprintf (gpath, 4095, "%s/%s", fma_global_path, 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) { | if ((ge_buffers[buf].fd = open (gpath, 0)) == -1) { |
| wprintw (wge_msg, "[FAIL]\n"); | printf ("[FAIL]\n"); |
| wrefresh (wge_msg); | |
| return -1; | return -1; |
| } | } |
| else { | else { |
| wprintw (wge_msg, "[OK]\n"); | printf ("[OK]\n"); |
| wrefresh (wge_msg); | |
| } | } |
| fstat (ge_buffers[buf].fd, &sb); | fstat (ge_buffers[buf].fd, &sb); |
| Line 640 int ge_open_global(char *gblname) | Line 545 int ge_open_global(char *gblname) |
| return buf; | 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); | |
| } |