File:  [Coherent Logic Development] / freem / src / fma_gedit.c
Revision 1.7: download - view: text, annotated - select for diffs
Sun Apr 13 04:22:43 2025 UTC (3 months, 2 weeks ago) by snw
Branches: MAIN
CVS tags: HEAD
Fix snprintf calls

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

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