Annotation of freem/src/fma_gedit.c, revision 1.7

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>