Annotation of freem/src/fma_gedit.c, revision 1.5
1.1 snw 1: /*
1.5 ! snw 2: * $Id: fma_gedit.c,v 1.4 2025/03/30 01:36:58 snw Exp $
1.1 snw 3: * FreeM global editor
4: *
5: *
1.2 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.3 snw 8: * Copyright (C) 2023, 2025 Coherent Logic Development LLC
1.1 snw 9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
1.4 snw 26: * $Log: fma_gedit.c,v $
1.5 ! snw 27: * Revision 1.4 2025/03/30 01:36:58 snw
! 28: * Make it easier to bring back fma_gedit, fix double-free in global handler, limit $CHAR to 7-bit ASCII
! 29: *
1.4 snw 30: * Revision 1.3 2025/03/09 19:14:24 snw
31: * First phase of REUSE compliance and header reformat
32: *
1.3 snw 33: *
34: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
35: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 36: **/
37:
38: #include <stdlib.h>
39: #include <stdio.h>
40: #include <stdlib.h>
41: #include <string.h>
42: #include <dirent.h>
43: #include <time.h>
44: #include <unistd.h>
45: #include <sys/types.h>
46: #include <sys/stat.h>
47: #include <fcntl.h>
48:
49: #include "fmadm.h"
50: #include "fma_globals.h"
51:
1.5 ! snw 52: #ifdef HAVE_LIBREADLINE
! 53: # if defined(HAVE_READLINE_READLINE_H)
! 54: # include <readline/readline.h>
! 55: # elif defined(HAVE_READLINE_H)
! 56: # include <readline.h>
! 57: # else /* !defined(HAVE_READLINE_H) */
! 58: extern char *readline ();
! 59: # endif /* !defined(HAVE_READLINE_H) */
! 60: /*char *cmdline = NULL;*/
! 61: #else /* !defined(HAVE_READLINE_READLINE_H) */
! 62: /* no readline */
! 63: #endif /* HAVE_LIBREADLINE */
! 64:
! 65: #ifdef HAVE_READLINE_HISTORY
! 66: # if defined(HAVE_READLINE_HISTORY_H)
! 67: # include <readline/history.h>
! 68: # elif defined(HAVE_HISTORY_H)
! 69: # include <history.h>
! 70: # else /* !defined(HAVE_HISTORY_H) */
! 71: extern void add_history ();
! 72: extern int write_history ();
! 73: extern int read_history ();
! 74: # endif /* defined(HAVE_READLINE_HISTORY_H) */
! 75: /* no history */
! 76: #endif /* HAVE_READLINE_HISTORY */
! 77:
! 78:
1.1 snw 79:
80: #define GE_MXGBL 100
81:
82: typedef struct ge_key {
83: char key[256];
84: char data[256];
85:
86: struct ge_key *next;
87: } ge_key;
88:
89: typedef struct ge_blockinfo {
90:
91: int keylen;
92: int keyoffs;
93: char key[STRLEN];
94: int datalen;
95: char data[STRLEN];
96:
97: long llptr;
98: long rlptr;
99: long offset;
100:
101: long blockcount;
102: int collation;
103:
104: int btype;
105: char bt_desc[40];
106: long free_offset;
107:
108: long keyct;
109: ge_key *key_head;
110:
111: } ge_blockinfo;
112:
113:
114: typedef struct ge_buf {
115: char name[256];
116: char namespace[256];
117: char pth[4096];
118:
119: short fd;
120:
121: long blockct;
122: long gblsize;
123:
124: int blocknum;
125: char block_r[BLOCKLEN];
126: ge_blockinfo block;
127:
128: short block_dirty;
129: short is_free;
130: } ge_buf;
131:
132:
133: ge_buf ge_buffers[GE_MXGBL];
134:
135: int ge_curbuf;
136: int ge_nextbuf;
137:
138: int ge_rows;
139: int ge_columns;
140:
141: void ge_update_gbl(void);
142: void ge_select_buffer(int buf);
143: short ge_select_block(int buf, long blocknum);
144: void ge_update_block(void);
145: int ge_open_global(char *gblname);
146: void ge_init_buffers(void);
147: void ge_eventloop(void);
148: void ge_decode_key(const char *key, char *buf);
1.5 ! snw 149: void ge_describe_block(void);
1.1 snw 150:
151: #define SPC ' '
152:
1.5 ! snw 153:
! 154: void ge_describe_gbl(void)
! 155: {
! 156: printf ("global %s [#%d]\n", ge_buffers[ge_curbuf].name, ge_curbuf);
! 157: printf ("namespace %s\n", ge_buffers[ge_curbuf].namespace);
! 158: printf ("block size %d bytes\n", BLOCKLEN);
! 159: printf ("block count %d\n", ge_buffers[ge_curbuf].blockct);
! 160: printf ("file size %d bytes\n", ge_buffers[ge_curbuf].gblsize);
! 161: }
! 162:
! 163: void ge_update_gbl(void)
! 164: {
! 165: printf ("fmadm: selected global %s into buffer %d\n", ge_buffers[ge_curbuf].name, ge_curbuf);
! 166: }
! 167:
! 168:
1.1 snw 169: int fma_globals_edit(int optc, char **opts)
170: {
1.5 ! snw 171: #define MODE_GBL 0
! 172: #define MODE_BLK 1
! 173: #if defined(HAVE_LIBREADLINE) && !defined(_AIX)
1.1 snw 174: int editbuf;
1.5 ! snw 175: char fmge_prompt[256];
! 176: char *cmdt = (char *) malloc (65535 * sizeof (char));
! 177: char *fmarl_buf;
! 178: char **args;
! 179: int mode = MODE_GBL;
! 180: char *result = (char *) malloc (65535 * sizeof (char));;
! 181: int argc;
! 182: int tmpres;
! 183: register int i;
! 184:
! 185: /* first dimension */
! 186: if ((args = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {
! 187: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
! 188: return 1;
! 189: }
! 190:
! 191: /* second dimension */
! 192: for (i = 0; i < FMA_MAXARGS; i++) {
! 193: if ((args[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
! 194: fprintf (stderr, "fmadm [FATAL]: could not acquire memory\n");
! 195: return 1;
! 196: }
! 197: }
! 198:
1.1 snw 199:
200: ge_curbuf = 0;
201: ge_nextbuf = 0;
1.5 ! snw 202: ge_init_buffers ();
1.1 snw 203:
204: if (optc == 2) {
205:
206: if ((editbuf = ge_open_global (opts[fma_base_opt])) == -1) {
1.5 ! snw 207: fprintf (stderr, "fmadm: cannot open global %s\n", opts[fma_base_opt]);
1.1 snw 208: }
209: else {
210: ge_select_buffer (editbuf);
211: }
212:
213: }
214:
1.5 ! snw 215: while(1) {
! 216: if (mode == MODE_GBL) {
! 217: sprintf (fmge_prompt, "global edit %s [buf %d/%d]> ",
! 218: ge_buffers[ge_curbuf].name,
! 219: ge_curbuf,
! 220: GE_MXGBL);
! 221: }
! 222: else {
! 223: sprintf (fmge_prompt, "block edit %s [blk %d/%d]> ",
! 224: ge_buffers[ge_curbuf].name,
! 225: ge_buffers[ge_curbuf].blocknum,
! 226: ge_buffers[ge_curbuf].blockct);
! 227: }
! 228:
! 229: fmarl_buf = readline (fmge_prompt);
! 230: if (fmarl_buf == (char *) NULL) continue;
1.1 snw 231:
1.5 ! snw 232: cmdt = strtok (fmarl_buf, " ");
! 233: if (cmdt == (char *) NULL) continue;
1.1 snw 234:
1.5 ! snw 235: i = 0;
! 236: while ((result = strtok (NULL, " ")) != NULL) {
! 237: strcpy (args[i++], result);
! 238: }
1.1 snw 239:
1.5 ! snw 240: argc = i;
! 241:
! 242: for (i = 0; i < strlen (cmdt); i++) cmdt[i] = cmdt[i] | 0140;
1.1 snw 243:
1.5 ! snw 244: if (strcmp (cmdt, "exit") == 0 || strcmp (cmdt, "quit") == 0) {
! 245: return 0;
! 246: }
! 247: else if (strcmp (cmdt, "block") == 0) {
! 248: mode = MODE_BLK;
! 249: }
! 250: else if (strcmp (cmdt, "global") == 0) {
! 251: mode = MODE_GBL;
! 252: }
! 253: else if (strcmp (cmdt, "describe") == 0) {
! 254: if (mode == MODE_GBL) {
! 255: ge_describe_gbl ();
! 256: }
! 257: else {
! 258: ge_describe_block ();
! 259: }
! 260: }
! 261: else if (strcmp (cmdt, "open") == 0) {
! 262: if (mode == MODE_GBL) {
! 263: printf ("TODO\n");
! 264: }
! 265: else {
! 266: long blknum;
! 267: blknum = atoi (args[0]);
! 268: ge_select_block (ge_curbuf, blknum);
! 269: }
! 270: }
! 271: else {
! 272: printf ("fmadm: command %s not recognized\n", cmdt);
! 273: }
! 274:
! 275:
1.1 snw 276: }
1.5 ! snw 277: #endif
! 278:
1.1 snw 279:
1.5 ! snw 280: return 0;
1.1 snw 281: }
282:
283:
284: void ge_init_buffers(void)
285: {
286: register int i;
287: register int j;
288:
289: for (i = 0; i < GE_MXGBL; i++) {
290: ge_buffers[i].name[0] = '\0';
291: ge_buffers[i].namespace[0] = '\0';
292: ge_buffers[i].pth[0] = '\0';
293: ge_buffers[i].fd = 0;
294: ge_buffers[i].blocknum = 0;
295: ge_buffers[i].block_dirty = FALSE;
296: ge_buffers[i].is_free = TRUE;
297: ge_buffers[i].blockct = 0;
298: ge_buffers[i].gblsize = 0;
299:
300: for (j = 0; j < BLOCKLEN; j++) {
301: ge_buffers[i].block_r[j] = '\0';
302: }
303: }
304: }
305:
306:
307:
308:
309: void ge_select_buffer(int buf)
310: {
1.5 ! snw 311: printf ("fmadm: selected buffer %d\n", buf);
1.1 snw 312:
313: ge_curbuf = buf;
314:
315: ge_update_gbl ();
316: }
317:
318: short ge_select_block(int buf, long blocknum)
319: {
320: ge_blockinfo *b;
321: char *br;
1.5 ! snw 322: char key[2056];
! 323: char decoded[64096];
1.1 snw 324: long i;
325: long j;
326: long k;
327: long length;
328:
329: if ((blocknum < 0) || (blocknum > (ge_buffers[buf].blockct - 1))) {
1.5 ! snw 330: printf ("block number for global %s must be between 0 and %d\n", ge_buffers[buf].name, ge_buffers[buf].blockct - 1);
1.1 snw 331: return FALSE;
332: }
333:
334: b = &(ge_buffers[buf].block);
335: br = ge_buffers[buf].block_r;
336:
337: lseek (ge_buffers[buf].fd, blocknum * BLOCKLEN, 0);
338: read (ge_buffers[buf].fd, br, BLOCKLEN);
339:
340: ge_buffers[buf].blocknum = blocknum;
341: ge_buffers[buf].block_dirty = FALSE;
342:
343: b->btype = br[BTYP];
344: switch (b->btype) {
345:
346: case DATA:
347: snprintf (b->bt_desc, 39, "DATA");
348: break;
349:
350: case POINTER:
351: snprintf (b->bt_desc, 39, "POINTER");
352: break;
353:
354: case BOTTOM:
355: snprintf (b->bt_desc, 39, "BTM PTR");
356: break;
357:
358: case EMPTY:
359: snprintf (b->bt_desc, 39, "EMPTY");
360: break;
361:
362: case FBLK:
363: snprintf (b->bt_desc, 39, "FBLK");
364: break;
365:
366: default:
367: snprintf (b->bt_desc, 39, "ILLEGAL TYPE");
368: break;
369:
370: }
371:
372: if (blocknum == ROOT) strcat (b->bt_desc, " [ROOT]");
373:
374: if (blocknum != ROOT) {
375: b->llptr = UNSIGN (br[LLPTR]) * 65536 + UNSIGN (br[LLPTR + 1]) * 256 + UNSIGN(br[LLPTR + 2]);
376: b->rlptr = UNSIGN (br[RLPTR]) * 65536 + UNSIGN (br[RLPTR + 1]) * 256 + UNSIGN(br[RLPTR + 2]);
377: }
378: else {
379: b->blockcount = UNSIGN (br[LLPTR]) * 65536 + UNSIGN (br[LLPTR + 1]) * 256 + UNSIGN(br[LLPTR + 2]);
380: b->free_offset = UNSIGN (br[RLPTR]) * 65536 + UNSIGN (br[RLPTR + 1]) * 256 + UNSIGN(br[RLPTR + 2]);
381: }
382:
383: b->offset = UNSIGN (br[OFFS]) * 256 + UNSIGN (br[OFFS + 1]);
384: b->keyct = 0;
385:
386: if (b->btype == FBLK) goto skip_keydec;
387:
388: i = 0;
389: while (i < b->offset) {
390:
391: length = UNSIGN (br[i++]);
392: k = UNSIGN (br[i++]);
393:
394: if ((i + length) > b->offset) break;
395:
396: for (j = 0; j < length; j++) {
397: key[k++] = br[i++];
398: }
399:
400: key[k] = g_EOL;
401:
402: ge_decode_key (key, decoded);
1.5 ! snw 403:
! 404: printf ("found key %s\n", decoded);
1.1 snw 405:
406: b->keyct++;
407: }
408:
409: skip_keydec:
410:
411: ge_update_block ();
412:
413: return TRUE;
414: }
415:
416: void ge_decode_key(const char *key, char *buf)
417: {
418: int ch;
419: short ch0;
420: short i;
421: short j;
422: short k;
423: short typ;
424:
425: j = 0;
426: i = 0;
427: k = 1;
428:
429: buf[j++] = '(';
430:
431: while ((ch = UNSIGN (key[i++])) != g_EOL) {
432:
433: if (k) {
434:
435: k = 0;
436:
437: if ((typ = (ch > SPC))) {
438: buf[j++] = '"';
439: }
440:
441: }
442:
443: ch0 = (ch >= SPC ? (ch >> 1) : (ch < 20 ? (ch >> 1) + '0' : (ch >> 1) + SPC));
444:
445: if (ch0 == DEL) {
446: if (((ch = UNSIGN (key[i++])) >> 1) == DEL) {
447: ch0 += DEL;
448: ch = UNSIGN (key[i++]);
449: }
450:
451: ch0 += (ch >> 1);
452: buf[j] = '<';
453: buf[++j] = '0' + ch0 / 100;
454: buf[++j] = '0' + (ch0 % 100) / 10;
455: buf[++j] = '0' + ch0 % 10;
456: buf[++j] = '>';
457: }
458: else {
459: buf[j] = ch0;
460: }
461:
462: if (buf[j++] == '"') {
463: buf[j++] = '"';
464: }
465:
466: if (ch & 01) {
467: if (typ) buf[j++] = '"';
468: buf[j++] = ',';
469: k = 1;
470: }
471: }
472:
473: buf[j--] = 0;
474: buf[j] = ')';
475: if (j == 0) buf[0] = 0;
476:
477: while (j >= 0) {
478: if ((ch = buf[--j]) < SPC || ch >= DEL) break;
479: }
480:
481: }
482:
1.5 ! snw 483: void ge_describe_block(void)
1.1 snw 484: {
1.5 ! snw 485: printf ("type = %s\n", ge_buffers[ge_curbuf].block.bt_desc);
1.1 snw 486:
487: if (ge_buffers[ge_curbuf].blocknum != ROOT) {
1.5 ! snw 488: printf ("llptr = %d\n", ge_buffers[ge_curbuf].block.llptr);
! 489: printf ("rlptr = %d\n", ge_buffers[ge_curbuf].block.rlptr);
1.1 snw 490: }
491: else {
1.5 ! snw 492: printf ("block count = %d\n", ge_buffers[ge_curbuf].block.blockcount);
! 493: printf ("offset to free space = %d\n", ge_buffers[ge_curbuf].block.free_offset);
! 494: }
! 495:
! 496: printf ("key count = %d\n", ge_buffers[ge_curbuf].block.keyct);
! 497: }
! 498:
! 499: void ge_update_block(void)
! 500: {
! 501:
! 502: printf ("fmadm: selected block %d of %d\n", ge_buffers[ge_curbuf].blocknum, ge_buffers[ge_curbuf].blockct);
! 503:
1.1 snw 504: }
505:
506: int ge_open_global(char *gblname)
507: {
508: char gpath[4096];
509: int buf;
510: struct stat sb;
511:
512: buf = ge_nextbuf++;
513:
514: snprintf (gpath, 4095, "%s/%s", fma_global_path, gblname);
515:
1.5 ! snw 516: printf ("fmadm: opening global %s [path %s, namespace %s]... ", gblname, gpath, fma_namespace);
1.1 snw 517:
518: if ((ge_buffers[buf].fd = open (gpath, 0)) == -1) {
1.5 ! snw 519: printf ("[FAIL]\n");
1.1 snw 520: return -1;
521: }
522: else {
1.5 ! snw 523: printf ("[OK]\n");
1.1 snw 524: }
525:
526: fstat (ge_buffers[buf].fd, &sb);
527:
528: ge_buffers[buf].gblsize = sb.st_size;
529: ge_buffers[buf].blockct = sb.st_size / BLOCKLEN;
530:
531: strcpy (ge_buffers[buf].name, gblname);
532: strcpy (ge_buffers[buf].namespace, fma_namespace);
533: strcpy (ge_buffers[buf].pth, gpath);
534:
535: ge_buffers[buf].blocknum = 0;
536: ge_buffers[buf].block_dirty = FALSE;
537:
538: ge_curbuf = buf;
539:
540: ge_select_block (buf, 0);
541:
542: return buf;
543: }
544:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>