Annotation of freem/src/fma_gedit.c, revision 1.1
1.1 ! snw 1: /*
! 2: * *
! 3: * * *
! 4: * * *
! 5: * ***************
! 6: * * * * *
! 7: * * MUMPS *
! 8: * * * * *
! 9: * ***************
! 10: * * *
! 11: * * *
! 12: * *
! 13: *
! 14: * fma_gedit.c
! 15: * FreeM global editor
! 16: *
! 17: *
! 18: * Author: Serena Willis <jpw@coherent-logic.com>
! 19: * Copyright (C) 1998 MUG Deutschland
! 20: * Copyright (C) 2023 Coherent Logic Development LLC
! 21: *
! 22: *
! 23: * This file is part of FreeM.
! 24: *
! 25: * FreeM is free software: you can redistribute it and/or modify
! 26: * it under the terms of the GNU Affero Public License as published by
! 27: * the Free Software Foundation, either version 3 of the License, or
! 28: * (at your option) any later version.
! 29: *
! 30: * FreeM is distributed in the hope that it will be useful,
! 31: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 32: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 33: * GNU Affero Public License for more details.
! 34: *
! 35: * You should have received a copy of the GNU Affero Public License
! 36: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
! 37: *
! 38: **/
! 39:
! 40: #include <stdlib.h>
! 41: #include <stdio.h>
! 42: #include <stdlib.h>
! 43: #include <string.h>
! 44: #include <dirent.h>
! 45: #include <time.h>
! 46: #include <unistd.h>
! 47: #include <sys/types.h>
! 48: #include <sys/stat.h>
! 49: #include <fcntl.h>
! 50:
! 51: #include "fmadm.h"
! 52: #include "fma_globals.h"
! 53:
! 54: #if defined HAVE_NCURSESW_CURSES_H
! 55: # include <ncursesw/curses.h>
! 56: #elif defined HAVE_NCURSESW_H
! 57: # include <ncursesw.h>
! 58: #elif defined HAVE_NCURSES_CURSES_H
! 59: # include <ncurses/curses.h>
! 60: #elif defined HAVE_NCURSES_H
! 61: # include <ncurses.h>
! 62: #elif defined HAVE_CURSES_H
! 63: # include <curses.h>
! 64: #else
! 65: # error "SysV or X/Open-compatible Curses header file required"
! 66: #endif
! 67:
! 68: #define GE_MXGBL 100
! 69:
! 70: typedef struct ge_key {
! 71: char key[256];
! 72: char data[256];
! 73:
! 74: struct ge_key *next;
! 75: } ge_key;
! 76:
! 77: typedef struct ge_blockinfo {
! 78:
! 79: int keylen;
! 80: int keyoffs;
! 81: char key[STRLEN];
! 82: int datalen;
! 83: char data[STRLEN];
! 84:
! 85: long llptr;
! 86: long rlptr;
! 87: long offset;
! 88:
! 89: long blockcount;
! 90: int collation;
! 91:
! 92: int btype;
! 93: char bt_desc[40];
! 94: long free_offset;
! 95:
! 96: long keyct;
! 97: ge_key *key_head;
! 98:
! 99: } ge_blockinfo;
! 100:
! 101:
! 102: typedef struct ge_buf {
! 103: char name[256];
! 104: char namespace[256];
! 105: char pth[4096];
! 106:
! 107: short fd;
! 108:
! 109: long blockct;
! 110: long gblsize;
! 111:
! 112: int blocknum;
! 113: char block_r[BLOCKLEN];
! 114: ge_blockinfo block;
! 115:
! 116: short block_dirty;
! 117: short is_free;
! 118: } ge_buf;
! 119:
! 120:
! 121: ge_buf ge_buffers[GE_MXGBL];
! 122:
! 123: int ge_curbuf;
! 124: int ge_nextbuf;
! 125:
! 126: int ge_rows;
! 127: int ge_columns;
! 128:
! 129: WINDOW *wge_key;
! 130: WINDOW *wge_key_border;
! 131: WINDOW *wge_node;
! 132: WINDOW *wge_node_border;
! 133: WINDOW *wge_msg_border;
! 134: WINDOW *wge_msg;
! 135: WINDOW *wge_block_border;
! 136: WINDOW *wge_block;
! 137: WINDOW *wge_global_border;
! 138: WINDOW *wge_global;
! 139: WINDOW *wge_command;
! 140:
! 141: WINDOW *wge_cur;
! 142:
! 143: void ge_set_wintitle(WINDOW *border_window, char *title);
! 144: void ge_wininit(void);
! 145: void ge_update_gbl(void);
! 146: void ge_select_buffer(int buf);
! 147: short ge_select_block(int buf, long blocknum);
! 148: void ge_update_block(void);
! 149: int ge_open_global(char *gblname);
! 150: void ge_init_buffers(void);
! 151: void ge_eventloop(void);
! 152: void ge_decode_key(const char *key, char *buf);
! 153: void ge_win_next(void);
! 154: void ge_win_previous(void);
! 155:
! 156: #define SPC ' '
! 157:
! 158: int fma_globals_edit(int optc, char **opts)
! 159: {
! 160: int editbuf;
! 161:
! 162: ge_curbuf = 0;
! 163: ge_nextbuf = 0;
! 164:
! 165: ge_init_buffers ();
! 166: initscr ();
! 167: ge_wininit ();
! 168:
! 169: wge_cur = wge_command;
! 170:
! 171: wprintw (wge_msg, "FreeM Global Editor\n");
! 172: wprintw (wge_msg, " Copyright (C) 2023 Coherent Logic Development LLC\n\n");
! 173:
! 174: wattron (wge_msg, A_BOLD);
! 175: wprintw (wge_msg, "Left and right arrow keys navigate blocks; 'q' to quit.\n\n");
! 176: wattroff (wge_msg, A_BOLD);
! 177: wrefresh (wge_msg);
! 178:
! 179: if (optc == 2) {
! 180:
! 181: if ((editbuf = ge_open_global (opts[fma_base_opt])) == -1) {
! 182: wprintw (wge_msg, "fmadm: cannot open global %s\n", opts[fma_base_opt]);
! 183: }
! 184: else {
! 185: ge_select_buffer (editbuf);
! 186: }
! 187:
! 188: }
! 189:
! 190: ge_eventloop ();
! 191:
! 192: endwin ();
! 193: return 0;
! 194: }
! 195:
! 196: void ge_win_next(void)
! 197: {
! 198:
! 199: /*
! 200: switch (wge_cur) {
! 201:
! 202: case wge_key:
! 203: wge_cur = wge_node;
! 204: break;
! 205:
! 206: case wge_node:
! 207: wge_cur = wge_global;
! 208: break;
! 209:
! 210: case wge_global:
! 211: wge_cur = wge_block;
! 212: break;
! 213:
! 214: case wge_block:
! 215: wge_cur = wge_command;
! 216: break;
! 217:
! 218: case wge_command:
! 219: wge_cur = wge_msg;
! 220: break;
! 221:
! 222: case wge_msg:
! 223: wge_cur = wge_key;
! 224: break;
! 225:
! 226: }
! 227: */
! 228:
! 229: }
! 230:
! 231:
! 232: void ge_win_previous(void)
! 233: {
! 234:
! 235: }
! 236:
! 237:
! 238: void ge_eventloop(void)
! 239: {
! 240: int c;
! 241: short quit_flag;
! 242:
! 243: quit_flag = FALSE;
! 244:
! 245: while (!quit_flag) {
! 246:
! 247: noecho ();
! 248: c = wgetch (wge_command);
! 249: echo ();
! 250:
! 251: switch (c) {
! 252:
! 253: case 'q':
! 254: case 'Q':
! 255: quit_flag = TRUE;
! 256: break;
! 257:
! 258: case KEY_LEFT:
! 259: if (ge_buffers[ge_curbuf].blocknum != 0) {
! 260: ge_select_block (ge_curbuf, ge_buffers[ge_curbuf].blocknum - 1);
! 261: }
! 262: else {
! 263: ge_select_block (ge_curbuf, ge_buffers[ge_curbuf].blockct - 1);
! 264: }
! 265: break;
! 266:
! 267: case KEY_RIGHT:
! 268: if (ge_buffers[ge_curbuf].blocknum + 1 < ge_buffers[ge_curbuf].blockct) {
! 269: ge_select_block (ge_curbuf, ge_buffers[ge_curbuf].blocknum + 1);
! 270: }
! 271: else {
! 272: ge_select_block (ge_curbuf, 0);
! 273: }
! 274: break;
! 275:
! 276: }
! 277:
! 278: }
! 279:
! 280: }
! 281:
! 282: void ge_init_buffers(void)
! 283: {
! 284: register int i;
! 285: register int j;
! 286:
! 287: for (i = 0; i < GE_MXGBL; i++) {
! 288: ge_buffers[i].name[0] = '\0';
! 289: ge_buffers[i].namespace[0] = '\0';
! 290: ge_buffers[i].pth[0] = '\0';
! 291: ge_buffers[i].fd = 0;
! 292: ge_buffers[i].blocknum = 0;
! 293: ge_buffers[i].block_dirty = FALSE;
! 294: ge_buffers[i].is_free = TRUE;
! 295: ge_buffers[i].blockct = 0;
! 296: ge_buffers[i].gblsize = 0;
! 297:
! 298: for (j = 0; j < BLOCKLEN; j++) {
! 299: ge_buffers[i].block_r[j] = '\0';
! 300: }
! 301: }
! 302: }
! 303:
! 304: void ge_wininit(void)
! 305: {
! 306: int half;
! 307:
! 308: getmaxyx (stdscr, ge_rows, ge_columns);
! 309:
! 310: half = ge_rows / 2;
! 311:
! 312: /* messages window */
! 313: wge_msg_border = newwin (10, ge_columns - 41, ge_rows - 12, 0);
! 314: wge_msg = newwin (8, ge_columns - 43, ge_rows - 11, 1);
! 315: ge_set_wintitle (wge_msg_border, "Messages");
! 316: wrefresh (wge_msg_border);
! 317: wrefresh (wge_msg);
! 318:
! 319: /* global window */
! 320: wge_global_border = newwin (half, 40, 0, ge_columns - 40);
! 321: wge_global = newwin (half - 2, 38, 1, ge_columns - 39);
! 322: ge_set_wintitle (wge_global_border, "No Global Selected");
! 323: wrefresh (wge_global_border);
! 324:
! 325: /* block window */
! 326: wge_block_border = newwin (half - 1, 40, half, ge_columns - 40);
! 327: wge_block = newwin (half - 3, 37, half + 1, ge_columns - 38);
! 328: ge_set_wintitle (wge_block_border, "Block");
! 329: wrefresh (wge_block_border);
! 330:
! 331: /* command window */
! 332: wge_command = newwin (1, ge_columns, ge_rows - 1, 0);
! 333: wrefresh (wge_command);
! 334:
! 335: scrollok (wge_msg, TRUE);
! 336: keypad (wge_command, TRUE);
! 337: keypad (wge_msg, TRUE);
! 338: keypad (wge_global, TRUE);
! 339: keypad (wge_block, TRUE);
! 340:
! 341: curs_set (0);
! 342: }
! 343:
! 344: void ge_update_gbl(void)
! 345: {
! 346: char wintit[4096];
! 347:
! 348: wclear (wge_global);
! 349: snprintf (wintit, 4095, "%s [#%d]", ge_buffers[ge_curbuf].name, ge_curbuf);
! 350: ge_set_wintitle (wge_global_border, wintit);
! 351:
! 352: wattron (wge_global, A_BOLD);
! 353: wprintw (wge_global, "GLOBAL: ");
! 354: wattroff (wge_global, A_BOLD);
! 355: wprintw (wge_global, "%s\n", ge_buffers[ge_curbuf].name);
! 356:
! 357: wattron (wge_global, A_BOLD);
! 358: wprintw (wge_global, "NAMESPACE: ");
! 359: wattroff (wge_global, A_BOLD);
! 360: wprintw (wge_global, "%s\n", ge_buffers[ge_curbuf].namespace);
! 361:
! 362: wattron (wge_global, A_BOLD);
! 363: wprintw (wge_global, "BLOCK SIZE: ");
! 364: wattroff (wge_global, A_BOLD);
! 365: wprintw (wge_global, "%d bytes\n", BLOCKLEN);
! 366:
! 367: wattron (wge_global, A_BOLD);
! 368: wprintw (wge_global, "BLOCK COUNT: ");
! 369: wattroff (wge_global, A_BOLD);
! 370: wprintw (wge_global, "%d\n", ge_buffers[ge_curbuf].blockct);
! 371:
! 372: wattron (wge_global, A_BOLD);
! 373: wprintw (wge_global, "FILE SIZE: ");
! 374: wattroff (wge_global, A_BOLD);
! 375: wprintw (wge_global, "%d bytes\n", ge_buffers[ge_curbuf].gblsize);
! 376:
! 377: wrefresh (wge_global);
! 378: }
! 379:
! 380:
! 381: void ge_select_buffer(int buf)
! 382: {
! 383: wprintw (wge_msg, "Selected buffer %d\n", buf);
! 384: wrefresh (wge_msg);
! 385:
! 386: ge_curbuf = buf;
! 387:
! 388: ge_update_gbl ();
! 389: }
! 390:
! 391: short ge_select_block(int buf, long blocknum)
! 392: {
! 393: ge_blockinfo *b;
! 394: char *br;
! 395: char key[256];
! 396: char decoded[4096];
! 397: long i;
! 398: long j;
! 399: long k;
! 400: long length;
! 401:
! 402: if ((blocknum < 0) || (blocknum > (ge_buffers[buf].blockct - 1))) {
! 403: wprintw (wge_msg, "Block number for global %s must be between 0 and %d\n", ge_buffers[buf].name, ge_buffers[buf].blockct - 1);
! 404: return FALSE;
! 405: }
! 406:
! 407: b = &(ge_buffers[buf].block);
! 408: br = ge_buffers[buf].block_r;
! 409:
! 410: lseek (ge_buffers[buf].fd, blocknum * BLOCKLEN, 0);
! 411: read (ge_buffers[buf].fd, br, BLOCKLEN);
! 412:
! 413: ge_buffers[buf].blocknum = blocknum;
! 414: ge_buffers[buf].block_dirty = FALSE;
! 415:
! 416: b->btype = br[BTYP];
! 417: switch (b->btype) {
! 418:
! 419: case DATA:
! 420: snprintf (b->bt_desc, 39, "DATA");
! 421: break;
! 422:
! 423: case POINTER:
! 424: snprintf (b->bt_desc, 39, "POINTER");
! 425: break;
! 426:
! 427: case BOTTOM:
! 428: snprintf (b->bt_desc, 39, "BTM PTR");
! 429: break;
! 430:
! 431: case EMPTY:
! 432: snprintf (b->bt_desc, 39, "EMPTY");
! 433: break;
! 434:
! 435: case FBLK:
! 436: snprintf (b->bt_desc, 39, "FBLK");
! 437: break;
! 438:
! 439: default:
! 440: snprintf (b->bt_desc, 39, "ILLEGAL TYPE");
! 441: break;
! 442:
! 443: }
! 444:
! 445: if (blocknum == ROOT) strcat (b->bt_desc, " [ROOT]");
! 446:
! 447: if (blocknum != ROOT) {
! 448: b->llptr = UNSIGN (br[LLPTR]) * 65536 + UNSIGN (br[LLPTR + 1]) * 256 + UNSIGN(br[LLPTR + 2]);
! 449: b->rlptr = UNSIGN (br[RLPTR]) * 65536 + UNSIGN (br[RLPTR + 1]) * 256 + UNSIGN(br[RLPTR + 2]);
! 450: }
! 451: else {
! 452: b->blockcount = UNSIGN (br[LLPTR]) * 65536 + UNSIGN (br[LLPTR + 1]) * 256 + UNSIGN(br[LLPTR + 2]);
! 453: b->free_offset = UNSIGN (br[RLPTR]) * 65536 + UNSIGN (br[RLPTR + 1]) * 256 + UNSIGN(br[RLPTR + 2]);
! 454: }
! 455:
! 456: b->offset = UNSIGN (br[OFFS]) * 256 + UNSIGN (br[OFFS + 1]);
! 457: b->keyct = 0;
! 458:
! 459: if (b->btype == FBLK) goto skip_keydec;
! 460:
! 461: i = 0;
! 462: while (i < b->offset) {
! 463:
! 464: length = UNSIGN (br[i++]);
! 465: k = UNSIGN (br[i++]);
! 466:
! 467: if ((i + length) > b->offset) break;
! 468:
! 469: for (j = 0; j < length; j++) {
! 470: key[k++] = br[i++];
! 471: }
! 472:
! 473: key[k] = g_EOL;
! 474:
! 475: ge_decode_key (key, decoded);
! 476: decoded[stlen (decoded)] = '\0';
! 477: wprintw (wge_msg, "found key %s\n", decoded);
! 478:
! 479: b->keyct++;
! 480: }
! 481:
! 482: skip_keydec:
! 483:
! 484: ge_update_block ();
! 485:
! 486: return TRUE;
! 487: }
! 488:
! 489: void ge_decode_key(const char *key, char *buf)
! 490: {
! 491: int ch;
! 492: short ch0;
! 493: short i;
! 494: short j;
! 495: short k;
! 496: short typ;
! 497:
! 498: j = 0;
! 499: i = 0;
! 500: k = 1;
! 501:
! 502: buf[j++] = '(';
! 503:
! 504: while ((ch = UNSIGN (key[i++])) != g_EOL) {
! 505:
! 506: if (k) {
! 507:
! 508: k = 0;
! 509:
! 510: if ((typ = (ch > SPC))) {
! 511: buf[j++] = '"';
! 512: }
! 513:
! 514: }
! 515:
! 516: ch0 = (ch >= SPC ? (ch >> 1) : (ch < 20 ? (ch >> 1) + '0' : (ch >> 1) + SPC));
! 517:
! 518: if (ch0 == DEL) {
! 519: if (((ch = UNSIGN (key[i++])) >> 1) == DEL) {
! 520: ch0 += DEL;
! 521: ch = UNSIGN (key[i++]);
! 522: }
! 523:
! 524: ch0 += (ch >> 1);
! 525: buf[j] = '<';
! 526: buf[++j] = '0' + ch0 / 100;
! 527: buf[++j] = '0' + (ch0 % 100) / 10;
! 528: buf[++j] = '0' + ch0 % 10;
! 529: buf[++j] = '>';
! 530: }
! 531: else {
! 532: buf[j] = ch0;
! 533: }
! 534:
! 535: if (buf[j++] == '"') {
! 536: buf[j++] = '"';
! 537: }
! 538:
! 539: if (ch & 01) {
! 540: if (typ) buf[j++] = '"';
! 541: buf[j++] = ',';
! 542: k = 1;
! 543: }
! 544: }
! 545:
! 546: buf[j--] = 0;
! 547: buf[j] = ')';
! 548: if (j == 0) buf[0] = 0;
! 549:
! 550: while (j >= 0) {
! 551: if ((ch = buf[--j]) < SPC || ch >= DEL) break;
! 552: }
! 553:
! 554: }
! 555:
! 556: void ge_update_block(void)
! 557: {
! 558: char wintit[4096];
! 559:
! 560: wclear (wge_block);
! 561: snprintf (wintit, 4095, "Block %d of %d", ge_buffers[ge_curbuf].blocknum, ge_buffers[ge_curbuf].blockct);
! 562: ge_set_wintitle (wge_block_border, wintit);
! 563:
! 564: wattron (wge_block, A_BOLD);
! 565: wprintw (wge_block, "TYPE: ");
! 566: wattroff (wge_block, A_BOLD);
! 567: wprintw (wge_block, "%s\n", ge_buffers[ge_curbuf].block.bt_desc);
! 568:
! 569: if (ge_buffers[ge_curbuf].blocknum != ROOT) {
! 570: wattron (wge_block, A_BOLD);
! 571: wprintw (wge_block, "LEFT LINK POINTER: ");
! 572: wattroff (wge_block, A_BOLD);
! 573: wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.llptr);
! 574:
! 575: wattron (wge_block, A_BOLD);
! 576: wprintw (wge_block, "RIGHT LINK POINTER: ");
! 577: wattroff (wge_block, A_BOLD);
! 578: wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.rlptr);
! 579: }
! 580: else {
! 581: wattron (wge_block, A_BOLD);
! 582: wprintw (wge_block, "BLOCK COUNT: ");
! 583: wattroff (wge_block, A_BOLD);
! 584: wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.blockcount);
! 585:
! 586: wattron (wge_block, A_BOLD);
! 587: wprintw (wge_block, "FREE OFFSET: ");
! 588: wattroff (wge_block, A_BOLD);
! 589: wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.free_offset);
! 590: }
! 591:
! 592: wattron (wge_block, A_BOLD);
! 593: wprintw (wge_block, "KEY COUNT: ");
! 594: wattroff (wge_block, A_BOLD);
! 595: wprintw (wge_block, "%d\n", ge_buffers[ge_curbuf].block.keyct);
! 596:
! 597: wrefresh (wge_block);
! 598: }
! 599:
! 600: int ge_open_global(char *gblname)
! 601: {
! 602: char gpath[4096];
! 603: int buf;
! 604: struct stat sb;
! 605:
! 606: buf = ge_nextbuf++;
! 607:
! 608: snprintf (gpath, 4095, "%s/%s", fma_global_path, gblname);
! 609:
! 610: wprintw (wge_msg, "Opening global %s [path %s, namespace %s]... ", gblname, gpath, fma_namespace);
! 611:
! 612: wrefresh (wge_msg);
! 613:
! 614: if ((ge_buffers[buf].fd = open (gpath, 0)) == -1) {
! 615: wprintw (wge_msg, "[FAIL]\n");
! 616: wrefresh (wge_msg);
! 617: return -1;
! 618: }
! 619: else {
! 620: wprintw (wge_msg, "[OK]\n");
! 621: wrefresh (wge_msg);
! 622: }
! 623:
! 624: fstat (ge_buffers[buf].fd, &sb);
! 625:
! 626: ge_buffers[buf].gblsize = sb.st_size;
! 627: ge_buffers[buf].blockct = sb.st_size / BLOCKLEN;
! 628:
! 629: strcpy (ge_buffers[buf].name, gblname);
! 630: strcpy (ge_buffers[buf].namespace, fma_namespace);
! 631: strcpy (ge_buffers[buf].pth, gpath);
! 632:
! 633: ge_buffers[buf].blocknum = 0;
! 634: ge_buffers[buf].block_dirty = FALSE;
! 635:
! 636: ge_curbuf = buf;
! 637:
! 638: ge_select_block (buf, 0);
! 639:
! 640: return buf;
! 641: }
! 642:
! 643: void ge_set_wintitle(WINDOW *border_window, char *title)
! 644: {
! 645: box (border_window, 0, 0);
! 646: wattron (border_window, A_BOLD);
! 647: mvwprintw (border_window, 0, 3, title);
! 648: wattroff (border_window, A_BOLD);
! 649: wrefresh (border_window);
! 650: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>