File:  [Coherent Logic Development] / freem / src / fma_gedit.c
Revision 1.5: download - view: text, annotated - select for diffs
Mon Mar 31 16:33:56 2025 UTC (12 months ago) by snw
Branches: MAIN
CVS tags: v0-63-1-rc1, v0-63-0-rc1, v0-63-0, HEAD
Work on fmadm edit global

    1: /*
    2:  *   $Id: fma_gedit.c,v 1.5 2025/03/31 16:33:56 snw Exp $
    3:  *    FreeM global editor
    4:  *
    5:  *  
    6:  *   Author: Serena Willis <snw@coherent-logic.com>
    7:  *    Copyright (C) 1998 MUG Deutschland
    8:  *    Copyright (C) 2023, 2025 Coherent Logic Development LLC
    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:  *
   26:  *   $Log: fma_gedit.c,v $
   27:  *   Revision 1.5  2025/03/31 16:33:56  snw
   28:  *   Work on fmadm edit global
   29:  *
   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:  *
   33:  *   Revision 1.3  2025/03/09 19:14:24  snw
   34:  *   First phase of REUSE compliance and header reformat
   35:  *
   36:  *
   37:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
   38:  * SPDX-License-Identifier: AGPL-3.0-or-later 
   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: 
   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: 
   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);
  152: void ge_describe_block(void);
  153: 
  154: #define SPC ' '
  155: 
  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);
  162:     printf ("block count %d\n", ge_buffers[ge_curbuf].blockct);
  163:     printf ("file size %d bytes\n", ge_buffers[ge_curbuf].gblsize);
  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: 
  172: int fma_globals_edit(int optc, char **opts)
  173: {
  174:     #define MODE_GBL 0
  175:     #define MODE_BLK 1
  176: #if defined(HAVE_LIBREADLINE) && !defined(_AIX)
  177:     int editbuf;        
  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));;
  184:     int argc;
  185:     int tmpres;
  186:     register int i;
  187: 
  188:     /* first dimension */
  189:     if ((args = (char **) malloc (FMA_MAXARGS * sizeof (char *))) == NULL) {	
  190:         fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
  191:         return 1;
  192:     } 
  193: 
  194:     /* second dimension */
  195:     for (i = 0; i < FMA_MAXARGS; i++) {
  196:         if ((args[i] = (char *) malloc (STRLEN * sizeof (char *))) == NULL) {
  197:             fprintf (stderr, "fmadm [FATAL]:  could not acquire memory\n");
  198:             return 1;
  199:         } 
  200:     }
  201: 
  202:     
  203:     ge_curbuf = 0;
  204:     ge_nextbuf = 0;
  205:     ge_init_buffers ();   
  206:     
  207:     if (optc == 2) {
  208:         
  209:         if ((editbuf = ge_open_global (opts[fma_base_opt])) == -1) {
  210:             fprintf (stderr, "fmadm:  cannot open global %s\n", opts[fma_base_opt]);
  211:         }
  212:         else {        
  213:             ge_select_buffer (editbuf);
  214:         }
  215:         
  216:     }
  217: 
  218:     while(1) {
  219:         if (mode == MODE_GBL) {
  220:             sprintf (fmge_prompt, "global edit %s [buf %d/%d]> ",
  221:                      ge_buffers[ge_curbuf].name,
  222:                      ge_curbuf,
  223:                      GE_MXGBL);
  224:         }
  225:         else {
  226:             sprintf (fmge_prompt, "block edit %s [blk %d/%d]> ",
  227:                      ge_buffers[ge_curbuf].name,
  228:                      ge_buffers[ge_curbuf].blocknum,
  229:                      ge_buffers[ge_curbuf].blockct);
  230:         }
  231:         
  232:         fmarl_buf = readline (fmge_prompt);
  233:         if (fmarl_buf == (char *) NULL) continue;
  234: 
  235:         cmdt = strtok (fmarl_buf, " ");
  236:         if (cmdt == (char *) NULL) continue;
  237: 
  238:         i = 0;
  239:         while ((result = strtok (NULL, " ")) != NULL) {        
  240:             strcpy (args[i++], result);
  241:         }
  242: 
  243:         argc = i;
  244:         
  245:         for (i = 0; i < strlen (cmdt); i++) cmdt[i] = cmdt[i] | 0140;
  246: 
  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:         
  279:     }
  280: #endif    
  281:         
  282: 
  283:     return 0;
  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: {        
  314:     printf ("fmadm:  selected buffer %d\n", buf);
  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;
  325:     char key[2056];
  326:     char decoded[64096];
  327:     long i;
  328:     long j;
  329:     long k;
  330:     long length;
  331:     
  332:     if ((blocknum < 0) || (blocknum > (ge_buffers[buf].blockct - 1))) {
  333:         printf ("block number for global %s must be between 0 and %d\n", ge_buffers[buf].name, ge_buffers[buf].blockct - 1);
  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:
  350:             snprintf (b->bt_desc, 39, "DATA");
  351:             break;
  352: 
  353:         case POINTER:
  354:             snprintf (b->bt_desc, 39, "POINTER");
  355:             break;
  356: 
  357:         case BOTTOM:
  358:             snprintf (b->bt_desc, 39, "BTM PTR");
  359:             break;
  360: 
  361:         case EMPTY:
  362:             snprintf (b->bt_desc, 39, "EMPTY");
  363:             break;
  364: 
  365:         case FBLK:
  366:             snprintf (b->bt_desc, 39, "FBLK");
  367:             break;
  368: 
  369:         default:
  370:             snprintf (b->bt_desc, 39, "ILLEGAL TYPE");
  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);
  406: 
  407:         printf ("found key %s\n", decoded);
  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: 
  486: void ge_describe_block(void)
  487: {
  488:     printf ("type = %s\n", ge_buffers[ge_curbuf].block.bt_desc);
  489: 
  490:     if (ge_buffers[ge_curbuf].blocknum != ROOT) {
  491:         printf ("llptr = %d\n", ge_buffers[ge_curbuf].block.llptr);        
  492:         printf ("rlptr = %d\n", ge_buffers[ge_curbuf].block.rlptr);
  493:     }
  494:     else {
  495:         printf ("block count = %d\n", ge_buffers[ge_curbuf].block.blockcount);
  496:         printf ("offset to free space = %d\n", ge_buffers[ge_curbuf].block.free_offset);
  497:     }
  498: 
  499:     printf ("key count = %d\n", ge_buffers[ge_curbuf].block.keyct);
  500: }
  501: 
  502: void ge_update_block(void)
  503: {
  504: 
  505:     printf ("fmadm:  selected block %d of %d\n", ge_buffers[ge_curbuf].blocknum, ge_buffers[ge_curbuf].blockct);
  506: 
  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:     
  517:     snprintf (gpath, 4095, "%s/%s", fma_global_path, gblname);
  518: 
  519:     printf ("fmadm:  opening global %s [path %s, namespace %s]... ", gblname, gpath, fma_namespace);
  520: 
  521:     if ((ge_buffers[buf].fd = open (gpath, 0)) == -1) {
  522:         printf ("[FAIL]\n");
  523:         return -1;
  524:     }
  525:     else {
  526:         printf ("[OK]\n");
  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>