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

1.1       snw         1: /*
1.6     ! snw         2:  *   $Id: fma_gedit.c,v 1.5 2025/03/31 16:33:56 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.6     ! snw        27:  *   Revision 1.5  2025/03/31 16:33:56  snw
        !            28:  *   Work on fmadm edit global
        !            29:  *
1.5       snw        30:  *   Revision 1.4  2025/03/30 01:36:58  snw
                     31:  *   Make it easier to bring back fma_gedit, fix double-free in global handler, limit $CHAR to 7-bit ASCII
                     32:  *
1.4       snw        33:  *   Revision 1.3  2025/03/09 19:14:24  snw
                     34:  *   First phase of REUSE compliance and header reformat
                     35:  *
1.3       snw        36:  *
                     37:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
                     38:  * SPDX-License-Identifier: AGPL-3.0-or-later 
1.1       snw        39:  **/
                     40: 
                     41: #include <stdlib.h>
                     42: #include <stdio.h>
                     43: #include <stdlib.h>
                     44: #include <string.h>
                     45: #include <dirent.h>
                     46: #include <time.h>
                     47: #include <unistd.h>
                     48: #include <sys/types.h>
                     49: #include <sys/stat.h>
                     50: #include <fcntl.h>
                     51: 
                     52: #include "fmadm.h"
                     53: #include "fma_globals.h"
                     54: 
1.5       snw        55: #ifdef HAVE_LIBREADLINE
                     56: #  if defined(HAVE_READLINE_READLINE_H)
                     57: #    include <readline/readline.h>
                     58: #  elif defined(HAVE_READLINE_H)
                     59: #    include <readline.h>
                     60: #  else /* !defined(HAVE_READLINE_H) */
                     61: extern char *readline ();
                     62: #  endif /* !defined(HAVE_READLINE_H) */
                     63: /*char *cmdline = NULL;*/
                     64: #else /* !defined(HAVE_READLINE_READLINE_H) */
                     65:   /* no readline */
                     66: #endif /* HAVE_LIBREADLINE */
                     67: 
                     68: #ifdef HAVE_READLINE_HISTORY
                     69: #  if defined(HAVE_READLINE_HISTORY_H)
                     70: #    include <readline/history.h>
                     71: #  elif defined(HAVE_HISTORY_H)
                     72: #    include <history.h>
                     73: #  else /* !defined(HAVE_HISTORY_H) */
                     74: extern void add_history ();
                     75: extern int write_history ();
                     76: extern int read_history ();
                     77: #  endif /* defined(HAVE_READLINE_HISTORY_H) */
                     78:   /* no history */
                     79: #endif /* HAVE_READLINE_HISTORY */
                     80: 
                     81: 
1.1       snw        82: 
                     83: #define GE_MXGBL 100
                     84: 
                     85: typedef struct ge_key {
                     86:     char key[256];
                     87:     char data[256];
                     88: 
                     89:     struct ge_key *next;
                     90: } ge_key;
                     91: 
                     92: typedef struct ge_blockinfo {
                     93: 
                     94:     int keylen;
                     95:     int keyoffs;
                     96:     char key[STRLEN];
                     97:     int datalen;
                     98:     char data[STRLEN];
                     99: 
                    100:     long llptr;
                    101:     long rlptr;
                    102:     long offset;
                    103:     
                    104:     long blockcount;
                    105:     int collation;
                    106:     
                    107:     int btype;
                    108:     char bt_desc[40];
                    109:     long free_offset;
                    110: 
                    111:     long keyct;
                    112:     ge_key *key_head;
                    113: 
                    114: } ge_blockinfo;
                    115: 
                    116: 
                    117: typedef struct ge_buf {
                    118:     char name[256];
                    119:     char namespace[256];
                    120:     char pth[4096];
                    121:     
                    122:     short fd;
                    123: 
                    124:     long blockct;
                    125:     long gblsize;
                    126:     
                    127:     int blocknum;    
                    128:     char block_r[BLOCKLEN];
                    129:     ge_blockinfo block;
                    130:     
                    131:     short block_dirty;
                    132:     short is_free;
                    133: } ge_buf;
                    134: 
                    135: 
                    136: ge_buf ge_buffers[GE_MXGBL];
                    137: 
                    138: int ge_curbuf;
                    139: int ge_nextbuf;
                    140: 
                    141: int ge_rows;
                    142: int ge_columns;
                    143: 
                    144: void ge_update_gbl(void);
                    145: void ge_select_buffer(int buf);
                    146: short ge_select_block(int buf, long blocknum);
                    147: void ge_update_block(void);
                    148: int ge_open_global(char *gblname);
                    149: void ge_init_buffers(void);
                    150: void ge_eventloop(void);
                    151: void ge_decode_key(const char *key, char *buf);
1.5       snw       152: void ge_describe_block(void);
1.1       snw       153: 
                    154: #define SPC ' '
                    155: 
1.5       snw       156: 
                    157: void ge_describe_gbl(void)
                    158: {
                    159:     printf ("global %s [#%d]\n", ge_buffers[ge_curbuf].name, ge_curbuf);
                    160:     printf ("namespace %s\n", ge_buffers[ge_curbuf].namespace);
                    161:     printf ("block size %d bytes\n", BLOCKLEN);
1.6     ! snw       162:     printf ("block count %ld\n", ge_buffers[ge_curbuf].blockct);
        !           163:     printf ("file size %ld bytes\n", ge_buffers[ge_curbuf].gblsize);
1.5       snw       164: }
                    165: 
                    166: void ge_update_gbl(void)
                    167: {
                    168:     printf ("fmadm:  selected global %s into buffer %d\n", ge_buffers[ge_curbuf].name, ge_curbuf);
                    169: }
                    170:    
                    171: 
1.1       snw       172: int fma_globals_edit(int optc, char **opts)
                    173: {
1.5       snw       174:     #define MODE_GBL 0
                    175:     #define MODE_BLK 1
                    176: #if defined(HAVE_LIBREADLINE) && !defined(_AIX)
1.1       snw       177:     int editbuf;        
1.5       snw       178:     char fmge_prompt[256];
                    179:     char *cmdt = (char *) malloc (65535 * sizeof (char));
                    180:     char *fmarl_buf;
                    181:     char **args;
                    182:     int mode = MODE_GBL;
                    183:     char *result = (char *) malloc (65535 * sizeof (char));;
1.6     ! snw       184: /*    int argc;*/
1.5       snw       185:     register int i;
                    186: 
                    187:     /* first dimension */
                    188:     if ((args = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {   
                    189:         fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
                    190:         return 1;
                    191:     } 
                    192: 
                    193:     /* second dimension */
                    194:     for (i = 0; i < FMA_MAXARGS; i++) {
                    195:         if ((args[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
                    196:             fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
                    197:             return 1;
                    198:         } 
                    199:     }
                    200: 
1.1       snw       201:     
                    202:     ge_curbuf = 0;
                    203:     ge_nextbuf = 0;
1.5       snw       204:     ge_init_buffers ();   
1.1       snw       205:     
                    206:     if (optc == 2) {
                    207:         
                    208:         if ((editbuf = ge_open_global (opts[fma_base_opt])) == -1) {
1.5       snw       209:             fprintf (stderr, "fmadm:  cannot open global %s\n", opts[fma_base_opt]);
1.1       snw       210:         }
                    211:         else {        
                    212:             ge_select_buffer (editbuf);
                    213:         }
                    214:         
                    215:     }
                    216: 
1.5       snw       217:     while(1) {
                    218:         if (mode == MODE_GBL) {
1.6     ! snw       219:             snprintf (fmge_prompt, sizeof (fmge_prompt), "global edit %s [buf %d/%d]> ",
1.5       snw       220:                      ge_buffers[ge_curbuf].name,
                    221:                      ge_curbuf,
                    222:                      GE_MXGBL);
                    223:         }
                    224:         else {
1.6     ! snw       225:             snprintf (fmge_prompt, sizeof (fmge_prompt), "block edit %s [blk %d/%ld]> ",
1.5       snw       226:                      ge_buffers[ge_curbuf].name,
                    227:                      ge_buffers[ge_curbuf].blocknum,
                    228:                      ge_buffers[ge_curbuf].blockct);
                    229:         }
                    230:         
                    231:         fmarl_buf = readline (fmge_prompt);
                    232:         if (fmarl_buf == (char *) NULL) continue;
1.1       snw       233: 
1.5       snw       234:         cmdt = strtok (fmarl_buf, " ");
                    235:         if (cmdt == (char *) NULL) continue;
1.1       snw       236: 
1.5       snw       237:         i = 0;
                    238:         while ((result = strtok (NULL, " ")) != NULL) {        
                    239:             strcpy (args[i++], result);
                    240:         }
                    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.6     ! snw       330:         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       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.6     ! snw       488:         printf ("llptr = %ld\n", ge_buffers[ge_curbuf].block.llptr);        
        !           489:         printf ("rlptr = %ld\n", ge_buffers[ge_curbuf].block.rlptr);
1.1       snw       490:     }
                    491:     else {
1.6     ! snw       492:         printf ("block count = %ld\n", ge_buffers[ge_curbuf].block.blockcount);
        !           493:         printf ("offset to free space = %ld\n", ge_buffers[ge_curbuf].block.free_offset);
1.5       snw       494:     }
                    495: 
1.6     ! snw       496:     printf ("key count = %ld\n", ge_buffers[ge_curbuf].block.keyct);
1.5       snw       497: }
                    498: 
                    499: void ge_update_block(void)
                    500: {
                    501: 
1.6     ! snw       502:     printf ("fmadm:  selected block %d of %ld\n", ge_buffers[ge_curbuf].blocknum, ge_buffers[ge_curbuf].blockct);
1.5       snw       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>