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>