File:  [Coherent Logic Development] / freem / src / gcompact.c
Revision 1.3: download - view: text, annotated - select for diffs
Sun Mar 9 19:14:25 2025 UTC (3 weeks, 2 days ago) by snw
Branches: MAIN
CVS tags: v0-62-3, v0-62-2, v0-62-1, v0-62-0, HEAD
First phase of REUSE compliance and header reformat

/*
 *   $Id: gcompact.c,v 1.3 2025/03/09 19:14:25 snw Exp $
 *    global compactor
 *
 *  
 *   Author: Serena Willis <snw@coherent-logic.com>
 *    Copyright (C) 1998 MUG Deutschland
 *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
 *
 *
 *   This file is part of FreeM.
 *
 *   FreeM is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   FreeM is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero Public License for more details.
 *
 *   You should have received a copy of the GNU Affero Public License
 *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   $Log: gcompact.c,v $
 *   Revision 1.3  2025/03/09 19:14:25  snw
 *   First phase of REUSE compliance and header reformat
 *
 *
 * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
 * SPDX-License-Identifier: AGPL-3.0-or-later
 **/

/* compacts mumps globals.
* it is essential that the global structure is ok.
* because on certain errors (e.g. empty data block)
* large parts of data may be lost. errors in pointer
* blocks may be ignored, as long as the path to the first
* data block is ok.
*/
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#include <stddef.h>
#include "mpsdef0.h"
#include "errmsg.h"
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>


/* needed if byte data are to be interpreted as unsigned integer */
#define UNSIGN(A) ((A)&0377)

#define g_EOL 30
#define POINT 28
#define MINUS 26

#define ROOT 0L
/* length of blocks. status bytes defined as offset to blocklength */
#define DATALIM (BLOCKLEN-11)
#define LLPTR   (BLOCKLEN-10)
#define NRBLK    LLPTR
#define RLPTR   (BLOCKLEN- 6)
#define FREE     RLPTR
#define BTYP    (BLOCKLEN- 3)
#define OFFS    (BLOCKLEN- 2)

#define EMPTY    0
#define FBLK     1
#define POINTER  2
#define BOTTOM   6
#define DATA     8
/* error code */
#define PROTECT 30

#ifndef SYSFIVE
#define FreeM_timezone -3600
#else

#ifdef __CYGWIN__
#define FreeM_timezone _timezone
#else
extern long FreeM_timezone;
#endif /* __CYGWIN__ */

#endif /* SYSFIVE */


/* mumps commands */
#define BREAK       'b'
#define CLOSE       'c'
#define DO          'd'
#define DO_BLOCK     2
#define ELSE        'e'
#define FOR         'f'
#define GOTO        'g'
#define HA          'h'
#define HALT        '0'
#define HANG        '1'
#define IF          'i'
#define JOB         'j'
#define KILL        'k'
#define LOCK        'l'
#define NEW         'n'
#define OPEN        'o'
#define QUIT        'q'
#define READ        'r'
#define SET         's'
#define USE         'u'
#define VIEW        'v'
#define WRITE       'w'
#define XECUTE      'x'

#define ZALLOCATE   'A'
#define ZBREAK      'B'
#define ZDEALLOCATE 'D'
#define ZGO         'G'
#define ZHALT       'H'
#define ZINSERT     'I'
#define ZJOB        'J'
#define ZLOAD       'L'
#define ZNEW        'N'
#define ZPRINT      'P'
#define ZQUIT       'Q'
#define ZREMOVE     'R'
#define ZSAVE       'S'
#define ZTRAP       'T'
#define ZWRITE      'W'
#define PRIVATE     SP

extern short ierr;


int main (int argc, char **argv)
{
    
    char filnam[40];            /* global to be restored     */
    static char savnam[512] = "^/usr/tmp/"; /* intermediate storage      */
    static char unlnam[40] = "/usr/tmp/^";  /* "unlink" filename         */
    short fildes;           /* file descriptor to filnam */
    char block[BLOCKLEN];
    char key[512];
    char data[512];
    unsigned long blknbr;
    long offset;
    long type;
    long length;
    long koffs;

    register int i;
    register int j;
    register int k;
    register int ch;

    umask (0);              /* protection bits mask to full rights */
    filnam[0] = '^';
    filnam[1] = 0;

    if (argc > 1) {
    
        j = 0;
    
        while (--argc > 0) {
    
            j++;
    
            if (**(argv + j) == '-') {
                printf ("usage is: %s [^]global\012\015", *argv);
                exit (0);
            }
            
            strcpy (&filnam[1], *(argv + j));

        }
    
    } 
    else {
        printf ("\012\015%s global ^", *argv);
        scanf ("%s", &filnam[1]);
    }

    j = filnam[1];

    if (j == '.' || j == '/' || j == '^') {
        
        j = 0;
    
        while ((filnam[j] = filnam[j + 1])) j++;
    
    }
    
    if ((fildes = open (filnam, 0)) == -1) {
        printf ("cannot open file %s\007\012\015", filnam);
        exit (1);
    }

    strcpy (&savnam[10], &filnam[1]);
    
    koffs = 10 + strlen (&filnam[1]);
    
    strcpy (&unlnam[10], &filnam[1]);
    unlink (unlnam);            /* kill previous tmp_file */
    
    blknbr = ROOT;
    
    for (;;) {
        
        lseek (fildes, blknbr * BLOCKLEN, 0);
        
        if (read (fildes, block, BLOCKLEN) == 0) {
            printf ("\015*** something wrong ***\033[K\012\015");
            exit (0);
        }

        if (block[BTYP] == DATA) goto first;
        
        i = UNSIGN (block[0]) + 2;
        
        blknbr = UNSIGN (block[i]) * 65536 + UNSIGN (block[i + 1]) * 256 + UNSIGN (block[i + 2]);

    }


again:

    if (blknbr == 0) {
        
        printf ("\015*** done ***\033[K\012\015");
        
        strcpy (block, "mv /usr/tmp/\\^");
        strcat (block, &filnam[1]);
        strcat (block, " .");
        
        system (block);
        
        exit (0);

    }

    lseek (fildes, blknbr * BLOCKLEN, 0);
    
    if (read (fildes, block, BLOCKLEN) == 0) {
        
        strcpy (block, "mv /usr/tmp/\\^");
        strcat (block, &filnam[1]);
        strcat (block, " .");
        
        system (block);
        
        exit (0);

    }


first:             /* entry point for first DATA block */

    type = block[BTYP];

    blknbr = UNSIGN (block[RLPTR]) * 65536 +
    UNSIGN (block[RLPTR + 1]) * 256 +
    UNSIGN (block[RLPTR + 2]);

    if (type != DATA) goto again;
    
    offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);

    i = 0;

    while (i < offset) {
        
        length = UNSIGN (block[i++]);
        k = UNSIGN (block[i++]);
    
        if ((i + length) > offset) break;
        
        for (j = 0; j < length; j++) key[k++] = block[i++];
        
        key[k] = g_EOL;
        
        {

            long ch0;
            long i;
            long j;
            long k;

            j = 0;
            i = 0;

            data[j++] = DELIM;
            
            k = 1;
            
            while ((ch = UNSIGN (key[i++])) != g_EOL) {

                if (k) k = 0;
                
                ch0 = (ch >= SP ? (ch >> 1) :   /* 'string' chars */
                (ch < 20 ? (ch >> 1) + '0' :    /* 0...9          */
                (ch >> 1) + SP));   /* '.' or '-'     */
                
                if (ch0 == DEL) {
                    
                    if (((ch = UNSIGN (key[i++])) >> 1) == DEL) {
                        
                        ch0 += DEL;
                        ch0 = UNSIGN (key[i++]);
                
                    }
                    
                    ch0 += (ch >> 1);
                
                }
                
                data[j++] = ch0;
                
                if (ch & 01) {
                    data[j++] = DELIM;
                    k = 1;
                }

            }

            data[j--] = EOL;
            
            if (j == 0) {
                data[0] = EOL;
            }
            else if (data[j] == DELIM) {
                data[j] = EOL;
            }

            while (j >= 0) {
                if ((UNSIGN (ch = data[--j]) < SP) && (ch != DELIM)) break;
            }

            if (j < 0) {
                stcpy (&savnam[koffs], data);
            }
            else {
                goto again;
            }               /* illegal subscipt */

        }

        length = UNSIGN (block[i++]);
        k = 0;

        if ((i + length) > offset) break;

        stcpy0 (data, &block[i], length);
        
        i += length;
        data[length] = EOL;

        global  (0, savnam, data);  /* call original global */

        if (merr () == PROTECT) {
            printf ("\012cannot open intermediate file in /usr/tmp\012");
            exit (1);
        }

    }
    
    if (i != offset) printf ("\012wrong offset %ld vs. %d\012", offset, i);

    goto again;
}

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