/*
* $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>