Annotation of freem/src/fma_gedit.c, revision 1.1.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>