/*
* $Id: global_bltin.c,v 1.7 2025/03/24 04:13:11 snw Exp $
* freem database engine
*
*
* 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: global_bltin.c,v $
* Revision 1.7 2025/03/24 04:13:11 snw
* Replace action macro dat with fra_dat to avoid symbol conflict on OS/2
*
* Revision 1.6 2025/03/24 01:33:30 snw
* Guard declaration of time function in global_bltin.c for portability
*
* Revision 1.5 2025/03/22 22:52:24 snw
* Add STRLEN_GBL macro to manage global string length
*
* Revision 1.4 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
**/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "mpsdef.h"
static void b_free (short filedes, unsigned long blknbr);
static void splitp (short filedes, char *block, long *addr, long *offs, unsigned long *blknbr);
static void update (short filedes, char *ins_key, long keyl);
static void insert (int filedes, char *ins_key, long key_len, unsigned long blknbr);
static void scanpblk (char *block, long *adr, long *fnd);
static void scandblk (char *block, long *adr, long *fnd);
static void getnewblk (int filedes, unsigned long *blknbr);
static short int g_collate (char *t);
//static short int g_numeric (char *str);
short g_numeric (char *str);
void close_all_globals(void);
static void panic (void);
#define ROOT 0L
/* end of line symbol in global module is 30, which is a code not */
/* otherwise used in subscripts */
#define g_EOL 30
#define EOL1 EOL
/* numerics (('.'<<1)&037)==28 ; (('-'<<1)&037)==26; */
#define POINT 28
#define MINUS 26
/* ALPHA and OMEGA are dummy subscripts in $order processing */
/* ALPHA sorts before all other subscripts */
/* OMEGA sorts after all other subscripts */
/* e.g. ("abc") -> "abc",OMEGA ; ("abc","") -> "abc",ALPHA */
#define OMEGA 29
#define ALPHA 31
/* length of blocks. status bytes defined as offset to blocklength */
/* BLOCKLEN 1024 is defined in mpsdef0 include file */
#define DATALIM (BLOCKLEN-11)
#define LLPTR (BLOCKLEN-10)
#define NRBLK LLPTR
#define COLLA (BLOCKLEN- 7)
#define RLPTR (BLOCKLEN- 6)
#define FREE RLPTR
#define BTYP (BLOCKLEN- 3)
#define OFFS (BLOCKLEN- 2)
/* length of blockpointers in bytes */
#define PLEN 3
#define EMPTY 0
#define FBLK 1
#define POINTER 2
#define BOTTOM 6
#define DATA 8
#if !defined(__OpenBSD__) && !defined(_AIX) && !defined(__osf__) && !defined(MSDOS) && !defined(__vax__) && !defined(__OS2__)
long time ();
#endif
/* globals management */
/* 0 = set_sym 1 = get_sym */
/* 2 = kill_sym 3 = $data */
/* 5 = $fra_order */
/* 7 = $fra_query */
/* */
/* 14=killone 13=getnext */
/* 16=merge_sym 17=$zdata */
/* gvn as ASCII-string */
/* returns OK action fulfilled */
/* (ierr) UNDEF missing in action */
/* NAKED illegal naked reference */
/* SBSCR illegal subscript */
/* DBDGD data base degradation */
/* The data is organized in a B* tree structure on external storage.
* For a description of the principles of the algorithms see
* Donald E. Knuth "The Art of Computer Programming" vol. 3 p. 478.
* This tree structure guarantees fast disk access and is the
* canonical way to implement M globals.
*
* Each M global occupies a separate UNIX file in the directory
* specified in the globals_path directive for the current namespace
* in /etc/freem.conf. The default namespace on a new installation
* of FreeM is called "USER".
*
* Any global whose name begins with "%" will always be stored in the
* SYSTEM namespace, in the directory specified in its "globals_path"
* directive in /etc/freem.conf (by default, /var/local/freem/SYSTEM/globals).
*
* The UNIX file names are the same as the corresponding M global
* names; i.e. beginning with an '^'. However it is possible to access
* globals in other directories if the path name is specified.
* E.g. "S ^/usr/mumps/test=1" does "S ^test=1" in the file /usr/mumps/^test.
* If FreeM is started with the -s/--standard switches, it is not possible
* to specify a directory. There is a syntactic ambiguity: the '/' character
* in the directory name is in conflict with the '/' divide operator. Use
* parentheses to make things clear:
*
* ^/usr/mumps/test/2 ; '/2' is part of the name
* (^/usr/mumps/test)/2 ; ambiguity resolved
* ^test/2 ; '/2' is a divide operation
* ^/usr/mumps/test("ok")/2 ; '/2' is a divide
*
* To prevent jobs from messing the globals up, access is regulated
* with the 'locking' mechanism. (that is different from mumps LOCKs)
*
* Data is organized in blocks of 1024 bytes (BLOCKLEN) with the following
* layout:
* byte 0 - 1013 'stuff' 0...DATALIM
* organization is:
* length of key (minus offset into previous key)
* offset into previous key
* key (without EOL character)
* length of data or two bytes as pointer
* data(without EOL character) in pointer blocks
*
* byte 1014 - 1016 leftlink pointer LLPTR
* in root block: number of blocks NRBLK
* byte 1017 <reserved>
* byte 1017 in root block: type of collating sequence COLLA
* LSB=0: numeric(standard) LSB=1: alphabetic
* byte 1018 - 1020 rightlink pointer RLPTR
* in root block: number of free blocks list FREE
* byte 1021 block type BTYP
* (2=POINTER,6=BOTTOM LEVEL POINTER,8=DATA)
* byte 1022 - 1023 offset OFFS
* (pointer to unused part of 'stuff')
*
* the file is *not* closed on return. since access is regulated by the
* locking mechanism, that will not spell trouble.
*/
void global_bltin (short action, char *key, char *data)
{
/* these must be static variables */
static short filedes; /* filedescr for global access */
static char filnam[256]; /* name of global/unix file */
/* the following vars may be */
/* static or dynamic */
static unsigned long blknbr; /* block number */
static unsigned long oldblk;
static unsigned long newblk;
static unsigned long other;
static long j1;
static long limit;
static short typ; /* block type */
static long keyl, /* length of compacted key */
datal, /* length of data */
olddatal,
offset,
found,
addr, /* address of key in 'block' */
needed, /* new bytes needed to ins. stuff */
ret_to, /* return code */
kill_again;
static char key1[256];
static char tmp1[256]; /* intermediate storage for op= */
static char block[BLOCKLEN];
static int getnflag; /* flag 1=$ZO-variable 0=$Q-function */
static int tryfast; /* try fast access if get_sym on */
/* previous global */
struct stat dinf; /* get modification date */
long savj,
savch; /* saved j and ch for multiple pathes */
register long int i,
j,
k,
ch;
long pathscan; /* flag for repeated scan of pathlist setting an undef global */
/* process optional limitations */
if (glvnflag.all && key[0] >= '%' && key[0] <= 'z') {
if ((i = glvnflag.one[0])) { /* number of significant chars */
j = 0;
while ((k = key[j]) != DELIM && k != EOL) {
if (j >= i) {
while ((k = key[++j]) != DELIM && k != EOL);
stcpy (&key[i], &key[j]);
break;
}
j++;
}
}
if (glvnflag.one[1]) { /* upper/lower sensitivity */
j = 0;
while ((k = key[j]) != DELIM && k != EOL) {
if (k >= 'a' && k <= 'z') key[j] = k - 32;
j++;
}
}
if ((i = glvnflag.one[2])) {
if (stlen (key) > i) {
merr_raise (M75);
return;
} /* key length limit */
}
if ((i = glvnflag.one[3])) { /* subscript length limit */
j = 0;
while ((k = key[j++]) != DELIM && k != EOL);
if (k == DELIM) {
k = 0;
for (;;) {
k = key[j++];
if (k == DELIM || k == EOL) {
if (k > i) {
merr_raise (M75);
return;
}
k = 0;
}
if (k == EOL) break;
k++;
}
}
}
}
if (action == getnext) {
getnflag = TRUE;
varnam[0] = EOL;
if (zref[0] == EOL) {
merr_raise (M7);
data[0] = EOL;
return;
}
stcpy (key, zref);
action = fra_query;
ordercnt = 1L;
}
else {
getnflag = FALSE;
/* naked reference section */
if (key[1] == DELIM) { /* resolve naked reference */
while (--nakoffs >= 0) { /* naked reference pointer */
if (zref[nakoffs] == DELIM) break;
}
if ((i = ++nakoffs) == 0) { /* illegal naked reference */
data[0] = EOL1;
merr_raise (NAKED);
return;
}
j = 2;
while ((zref[i] = key[j++]) != EOL) {
if ((++i) >= STRLEN) {
zref[255] = EOL;
merr_raise (M75);
return;
}
}
nakoffs = stcpy (key, zref);
}
else {
/* only save off $REFERENCE if the global isn't part of SSVN backing storage */
if (key[1] != '$') {
nakoffs = stcpy (zref, key); /* save reference */
}
}
}
if (v22ptr) {
procv22 (key);
if (key[0] != '^') {
char losav[256];
stcpy (losav, l_o_val);
symtab (action, key, data);
stcpy (g_o_val, l_o_val);
stcpy (l_o_val, losav);
return;
}
}
/* construct full UNIX filename */
savj = 0;
savch = ch = EOL;
pathscan = TRUE;
nextpath:
k = 0;
j = savj;
if (key[1] == '%' || key[1] == '$') { /* %-globals and SSVN backing storage, no explicit path */
if (gloplib[0] != EOL) {
/* append % global access path */
while ((ch = filnam[k++] = gloplib[j++]) != ':' && ch != EOL);
}
}
else if (key[1] != '/') { /* no explicit path specified */
if (glopath[0] != EOL) {
/* append global access path */
while ((ch = filnam[k++] = glopath[j++]) != ':' && ch != EOL);
}
}
if (savj == 0 && ch == EOL) pathscan = FALSE; /* one path only: inhibit search */
if (k > 0) {
if (k == 1 || (k == 2 && filnam[0] == '.')) {
k = 0;
}
else {
filnam[k - 1] = '/';
}
}
savch = ch;
savj = j;
i = 0;
j = 0;
while (key[i] != EOL) {
if ((filnam[k] = key[i]) == DELIM) break;
if (filnam[k] == '/') {
j = i;
if (k > i) {
i = 0;
j = 0;
k = 0;
continue;
}
}
i++;
k++;
}
filnam[k] = NUL; /* NUL not EOL !!! */
/* if a unix directory is specified, reposition '^' */
/* '^/usr/test' becomes '/usr/^test' */
if (j > 0) {
for (k = 0; k < j; k++) {
filnam[k] = filnam[k + 1];
}
filnam[j] = '^';
}
/* compact key to internal format: characters are shifted left */
/* delimiters become LSB of previous character */
/* test subscripts for being numeric or not */
/* numeric values are shifted into the code space */
/* that is available because of illegal CTRL subscipts */
k = 0;
if (key[i] == EOL) { /* unsubscripted variable */
if (action == fra_order) {
g_o_val[0] = EOL;
merr_raise (NEXTER);
return;
}
}
else if (key[++i] == EOL) { /* empty (first) subscript */
if ((action != fra_order) && (action != fra_query)) {
merr_raise (SBSCR);
return;
}
}
else { /* non empty subscript */
j1 = g_numeric (&key[i]);
while ((ch = key[i++]) != EOL) {
if (ch == DELIM) {
if (k == 0) {
merr_raise (SBSCR);
return;
}
if (compactkey[--k] & 01) {
merr_raise (SBSCR);
return;
}
compactkey[k++] |= 01;
j1 = g_numeric (&key[i]);
}
else if (UNSIGN (ch) >= DEL) { /* transform 8bit char to 7bit */
compactkey[k++] = (DEL << 1);
ch = UNSIGN (ch) - DEL;
if (UNSIGN (ch) >= DEL) {
compactkey[k++] = (DEL << 1);
ch = UNSIGN (ch) - DEL;
}
compactkey[k++] = ch << 1;
}
else if (ch < SP || ch >= DEL) {
/*no CTRLs */
merr_raise (SBSCR);
return;
}
else {
compactkey[k++] = (j1 ? (ch << 1) & 036 : ch << 1);
}
}
}
if (action == fra_order) {
if (ordercnt > 0) {
compactkey[k] = (k == 0 || (compactkey[k - 1] & 01) ? ALPHA : OMEGA);
if (k > 0) compactkey[k - 1] |= 01;
keyl = (++k);
}
else if (ordercnt == 0) { /* no scan at all */
k = 0;
i = 0;
while ((ch = key[i++]) != EOL) {
if (ch == DELIM) k = i;
}
stcpy (data, &key[k]);
g_o_val[0] = EOL;
return;
}
else { /* backward scanning */
if (k == 0 || (compactkey[k - 1] & 01)) {
compactkey[k] = OMEGA;
if (k > 0) compactkey[k - 1] |= 01;
k++;
}
else {
compactkey[k - 1] |= 01;
}
keyl = k;
}
}
else {
if ((keyl = k) > 0) {
if ((compactkey[--k] & 01) && (action != fra_query)) {
merr_raise (SBSCR);
return;
}
compactkey[k++] |= 01;
}
}
compactkey[k] = g_EOL;
/* look whether file is already open */
tryfast = FALSE;
ch = usage[i = j = inuse];
while (i < NO_GLOBLS) {
k = 0;
while (filnam[k] == oldfil[i][k]) {
if (filnam[k++] == NUL) {
filedes = olddes[i];
if (inuse == i && action == get_sym) {
tryfast = TRUE;
if (usage[i] != (-1)) usage[i]++;
if (lonelyflag) goto tfast2;
fstat (filedes, &dinf);
if (g_ages[i] > dinf.st_mtime) goto tfast2;
g_ages[i] = time (0L);
goto tfast0;
}
inuse = i;
if (usage[i] != (-1)) usage[i]++;
goto lock;
}
}
if (ch < 0 || (usage[i] >= 0 && usage[i] < ch)) ch = usage[j = i];
if (i++ == inuse) {
inuse = (-1);
i = 0;
}
}
inuse = j;
usage[j] = 1;
/* close previous file */
if ((filedes = olddes[j]) > 0) {
close (filedes);
olddes[j] = 0;
}
strcpy (oldfil[j], filnam); /* save current filename */
reopen:
for (;;) {
errno = 0;
if ((filedes = open (filnam, 2)) != -1) break;
if (errno == EINTR) continue;
if (errno == EMFILE || errno == ENFILE) { /* too many open files now */
close_all_globals ();
continue;
}
break;
}
if (filedes == -1) {
usage[inuse] = 0;
oldfil[inuse][0] = NUL;
olddes[inuse] = 0;
g_ages[inuse] = 0;
if ((pathscan || errno != ENOENT) && (savch != EOL)) goto nextpath; /* try next access path */
/* file not found */
if (action != set_sym) {
if (errno != ENOENT) {
merr_raise (PROTECT);
return;
}
if (action == fra_dat || action == zdata) {
data[0] = '0';
data[1] = EOL1;
return;
}
data[0] = EOL1;
if (action == get_sym || getnflag) {
merr_raise (M7);
data[0] = EOL;
}
else if (action == fra_order || action == fra_query) {
g_o_val[0] = EOL;
}
return;
}
if (errno != ENOENT) {
merr_raise (PROTECT);
return;
}
if (pathscan) {
savj = 0;
savch = ch = EOL;
pathscan = FALSE;
goto nextpath;
}
if (setop) {
tmp1[0] = EOL;
m_op (tmp1, data, setop);
setop = 0;
if (merr () > OK) return;
datal = stcpy (data, tmp1);
}
for (i = 0; i < BLOCKLEN; block[i++] = 0); /* clear block */
stcpy0 (&block[2], compactkey, (long) keyl);
block[0] = keyl; /* $length of key */
j = i = keyl + 2;
block[i++] = 0;
block[i++] = 0;
block[i++] = ROOT + 1; /* block 1 = data */
block[BTYP] = BOTTOM;
block[COLLA] = 0; /* collating sequence */
block[OFFS] = i / 256;
block[OFFS + 1] = i % 256;
block[NRBLK] = 0;
block[NRBLK + 1] = 0;
block[NRBLK + 2] = ROOT + 1; /* nr. of blocks */
/* create file, write_lock it and initialize root block */
for (;;) {
errno = 0;
if ((filedes = creat (filnam, 0666)) != -1) break;
if (errno == EMFILE || errno == ENFILE) {
close_all_globals ();
continue;
}
merr_raise (PROTECT);
return;
}
if (lonelyflag == FALSE) locking (filedes, 1, 0L);
for (;;) {
errno = 0;
lseek (filedes, ROOT * BLOCKLEN, 0);
write (filedes, block, BLOCKLEN);
if (errno == 0) break;
panic ();
}
block[NRBLK] = 0;
block[NRBLK + 1] = 0;
block[NRBLK + 2] = ROOT; /* clear */
/* copy and write length of data */
block[j] = k = stcpy (&block[j + 1], data);
block[i = k + j + 1] = 0; /* clear EOL symbol */
block[BTYP] = DATA; /* type */
block[OFFS] = i / 256;
block[OFFS + 1] = i % 256;
for (;;) {
errno = 0;
write (filedes, block, BLOCKLEN);
if (errno == 0) break;
lseek (filedes, (ROOT + 1L) * BLOCKLEN, 0);
panic ();
}
close (filedes);
if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
/* close new file, so other users can find it */
return;
}
olddes[inuse] = filedes; /* save current filedescriptor */
/* request global for exclusive use */
/* odd numbered actions get read access (get_sym,data,fra_order) 3 */
/* even ones read/write access (set_sym,kill_sym) 1 */
lock:
if (action == get_sym) {
tfast0:
if (lonelyflag == FALSE) locking (filedes, 3, 0L);
if (tryfast) goto tfast1; /* try again last block */
blknbr = oldblk = ROOT; /* start with ROOT block */
for (;;) {
tfast1:
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
tfast2:
if ((typ = block[BTYP]) == DATA) { /* scan data block: here we test for equality only */
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
j = UNSIGN (block[0]);
i = 0;
stcpy0 (key1, &block[2], j); /* get first key */
ch = keyl; /* ch is a register! */
while (i < offset) {
j = UNSIGN (block[i++]); /* length of key - offset */
k = UNSIGN (block[i++]); /* offset into previous entry */
#ifdef VERSNEW
stcpy0 (&key0[k], &block[i], j);
i += j;
j += k;
#else
j += k;
while (k < j) key1[k++] = block[i++]; /* get key */
#endif /* VERSNEW */
if (j != ch) { /* keys have different length */
i += UNSIGN (block[i]);
i++;
continue;
}
/* key1[j]=g_EOL; */
j = ch;
do {
j--;
} while (compactkey[j] == key1[j]); /* compare keys */
if (j < 0) {
k = UNSIGN (block[i++]);
stcpy0 (data, &block[i], k); /* get value */
data[k] = EOL1; /* append EOL */
goto quit;
}
i += UNSIGN (block[i]);
i++; /* skip data */
}
/* fast access failed. try normal path */
if (tryfast) {
tryfast = FALSE;
goto tfast0;
}
merr_raise (M7);
data[0] = EOL;
goto quit; /* variable not found */
}
else {
if (tryfast) {
tryfast = FALSE;
goto tfast0;
}
if (typ == EMPTY) {
if (blknbr == ROOT) {
close (filedes);
goto reopen;
}
merr_raise (DBDGD);
goto quit;
}
}
scanpblk (block, &addr, &found);
addr += UNSIGN (block[addr]) + 2; /* skip key */
if ((blknbr = UNSIGN (block[addr]) * 65536 + UNSIGN (block[addr + 1]) * 256 + UNSIGN (block[addr + 2])) == oldblk) {
merr_raise (DBDGD);
goto quit;
}
addr += PLEN; /* skip data */
oldblk = blknbr;
if (merr () == INRPT) goto quit;
}
} /* end of get_sym */
if (lonelyflag == FALSE) locking (filedes, (action & 01 ? 3 : 1), 0L);
/* a KILL on an unsubscripted global deletes the entire file */
if (action == kill_sym && compactkey[0] == g_EOL) {
lseek (filedes, ROOT, 0);
/* note : UNIX does not tell other */
block[BTYP] = EMPTY; /* jobs that a file has been unlinked */
/* as long as they keep it open. */
/* so we mark this global as EMPTY */
write (filedes, block, BLOCKLEN);
if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
close (filedes);
olddes[inuse] = 0;
oldfil[inuse][0] = NUL;
usage[inuse] = 0;
unlink (filnam);
return;
}
k_again: /* entry point for repeated kill operations */
/* scan tree for the proper position of key */
blknbr = oldblk = ROOT; /* start with ROOT block */
trx = (-1);
for (;;) {
if (++trx >= TRLIM) {
merr_raise (STKOV);
goto quit;
}
traceblk[trx] = blknbr;
traceadr[trx] = 0;
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
typ = block[BTYP];
if (typ == DATA) {
scandblk (block, &addr, &found);
break;
}
if (typ == EMPTY) {
if (blknbr == ROOT) {
close (filedes);
goto reopen;
}
merr_raise (DBDGD);
goto quit;
}
scanpblk (block, &addr, &found);
traceadr[trx] = addr;
addr += UNSIGN (block[addr]);
addr += 2; /* skip key */
if ((blknbr = UNSIGN (block[addr]) * 65536 + UNSIGN (block[addr + 1]) * 256 + UNSIGN (block[addr + 2])) == oldblk) {
merr_raise (DBDGD);
goto quit;
}
addr += PLEN; /* skip data */
oldblk = blknbr;
}
traceadr[trx] = addr;
switch (action) {
case set_sym:
datal = stlen (data);
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
if (found != 2) { /* new entry */
if (setop) {
tmp1[0] = EOL;
m_op (tmp1, data, setop);
setop = 0;
if (merr () > OK) return;
datal = stcpy (data, tmp1);
}
needed = keyl + datal + 3;
if ((offset + needed) > DATALIM) {
ret_to = 'n'; /* n=new */
goto splitd;
}
s10: {
long len; /* insert key */
char key0[256];
i = 0;
while (i < addr) { /* compute offset into previous entry */
len = UNSIGN (block[i++]);
#ifdef VERSNEW
k = UNSIGN (block[i++]);
stcpy0 (&key0[k], &block[i], len);
i += len;
key0[k + len] = g_EOL;
#else
len += (k = UNSIGN (block[i++]));
while (k < len) key0[k++] = block[i++];
key0[k] = g_EOL;
#endif /* VERSNEW */
i += UNSIGN (block[i]);
i++; /* skip data */
}
k = 0;
if (addr > 0) {
while (compactkey[k] == key0[k]) {
if (key[k] == g_EOL) break;
k++;
}
/* do *not* fully compact numerics */
if ((i = UNSIGN (compactkey[k])) <= POINT) {
while (--k >= 0 && (UNSIGN (compactkey[k]) & 01) == 0);
k++;
}
}
needed -= k;
i = (offset += needed);
block[OFFS] = i / 256;
block[OFFS + 1] = i % 256;
while (i >= addr) {
block[i] = block[i - needed];
i--;
}
#ifdef VERSNEW
i = addr;
block[i++] = j1 = keyl - k;
block[i++] = k;
stcpy0 (&block[i], &compactkey[k], j1);
i += j1;
block[i++] = datal;
stcpy0 (&block[i], data, datal);
#else
block[addr + 1] = k;
j1 = k;
i = addr + 2;
while (k < keyl) block[i++] = compactkey[k++];
block[addr] = k - j1;
addr = i++;
k = 0;
while (k < datal) block[i++] = data[k++];
block[addr] = k;
#endif /* VERSNEW */
}
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
if (traceadr[trx] == 0) update (filedes, compactkey, keyl);
break;
}
/* there was a previous entry */
addr += UNSIGN (block[addr]);
addr += 2;
olddatal = UNSIGN (block[addr]);
if (setop) {
stcpy0 (tmp1, &block[addr + 1], (long) olddatal);
tmp1[olddatal] = EOL;
m_op (tmp1, data, setop);
setop = 0;
if (merr () > OK) return;
datal = stcpy (data, tmp1);
}
if ((j1 = olddatal - datal) != 0) {
if (j1 > 0) { /* surplus space */
i = addr + datal;
k = offset;
offset -= j1;
j1 += i;
stcpy0 (&block[i], &block[j1], offset - i);
i = offset;
while (i < k) block[i++] = 0; /* clear area */
}
else {
/* if (j1<0) */
/* we need more space */
if ((offset - j1) > DATALIM) {
/* block too small */
ret_to = 'u'; /* u=update */
goto splitd;
}
s20:
i = offset;
k = addr + olddatal;
offset -= j1;
j1 = offset;
while (i > k) block[j1--] = block[i--];
}
/* overwrite */
block[OFFS] = offset / 256;
block[OFFS + 1] = offset % 256;
block[addr] = datal;
}
else { /* if nothing changes, do not write */
i = 0;
j = addr + 1;
while (i < datal) {
if (block[j++] != data[i]) break;
i++;
}
if (i == datal) goto quit;
}
stcpy0 (&block[++addr], data, (long) datal);
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
break;
case fra_dat:
data[0] = '0';
data[1] = EOL1;
data[2] = EOL1;
if (found == 2) { /* ... advance to next entry */
addr += UNSIGN (block[addr]);
addr += 2; /* skip key */
addr += UNSIGN (block[addr]);
addr++; /* skip data */
data[0] = '1';
}
{
long len;
char key0[256];
/* get following entry, eventually in the next blk */
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
if (addr >= offset) {
if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]))) {
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
j1 = UNSIGN (block[0]);
i = 0;
j = 2;
while (i < j1) key0[i++] = block[j++];
key0[i] = g_EOL;
}
else {
goto quit;
}
}
else {
i = 0;
while (i <= addr) { /* compute offset complete key */
len = UNSIGN (block[i++]);
#ifdef VERSNEW
k = UNSIGN (block[i++]);
stcpy0 (&key0[k], &block[i], len);
key0[k + len] = g_EOL;
i += len;
#else
len += (j = UNSIGN (block[i++]));
while (j < len) key0[j++] = block[i++];
key0[j] = g_EOL;
#endif /* VERSNEW */
i += UNSIGN (block[i]);
i++; /* skip data */
}
}
/* is it a descendant? */
if (compactkey[0] == g_EOL && key0[0] != g_EOL) {
data[1] = data[0];
data[0] = '1';
break;
}
i = 0;
while (compactkey[i] == key0[i]) i++;
if (compactkey[i] == g_EOL) {
data[1] = data[0];
data[0] = '1';
}
}
break;
case fra_order:
if (ordercnt < 0) goto zinv;
offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
if (addr >= offset) { /* look in next block */
if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
data[0] = EOL1;
g_o_val[0] = EOL;
goto quit;
} /* no next block */
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
scandblk (block, &addr, &found);
}
{
long len;
int ch0;
char scratch[256];
char key0[256];
i = 0;
while (i <= addr) { /* compute offset complete key */
len = UNSIGN (block[i++]);
len += (j = UNSIGN (block[i++]));
while (j < len) key0[j++] = block[i++];
key0[j] = g_EOL;
i += UNSIGN (block[i]);
i++; /* skip data */
}
/* save data value for inspection with $V(111) */
i = addr;
i += UNSIGN (block[i]);
i += 2; /* skip key */
j = UNSIGN (block[i++]);
stcpy0 (g_o_val, &block[i], j); /* get value */
g_o_val[j] = EOL; /* append EOL */
i = 0;
j = 0;
while ((scratch[j++] = UNSIGN (key0[i++])) != g_EOL);
if (compactkey[--keyl] == ALPHA) keyl++;
/* count subscripts of key */
i = 0;
j1 = 0;
while (i < keyl) if (compactkey[i++] & 01)
j1++;
i = 0;
j = 0;
k = 0;
while (i < keyl) {
if (scratch[i] != compactkey[j++]) {
k++;
break;
}
if (scratch[i++] & 01) k++;
}
if (k < j1) {
data[0] = EOL1;
g_o_val[0] = EOL;
goto quit;
}
while (--i >= 0) {
if ((scratch[i] & 01)) break;
}
i++;
j = 0;
while ((ch = UNSIGN (scratch[i++])) != g_EOL) {
ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
(ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
(ch >> 1) + SP)); /* '.' or '-' */
if (ch0 == DEL) {
if (((ch = UNSIGN (scratch[i++])) >> 1) == DEL) {
ch0 += DEL;
ch = UNSIGN (scratch[i++]);
}
ch0 += (ch >> 1);
}
data[j++] = ch0;
if (ch & 01) break;
}
/* forget that data value if $d=10 */
if (UNSIGN (scratch[i]) != g_EOL) g_o_val[0] = EOL;
data[j] = EOL1;
ordercounter++;
if (--ordercnt > 0) { /* repeated forward scanning */
if (ch != g_EOL) scratch[i] = g_EOL;
stcpy0 (compactkey, scratch, i + 1);
compactkey[i - 1] |= 01;
compactkey[i] = OMEGA;
keyl = i + 1;
goto k_again;
}
}
break;
case fra_query:
if (ordercnt < 1) {
merr_raise (ARGLIST);
goto quit;
}
if (found == 2) { /* ... advance to next entry */
addr += UNSIGN (block[addr]);
addr += 2; /* skip key */
addr += UNSIGN (block[addr]);
addr++; /* skip data */
}
offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
while (--ordercnt > 0) { /* repeated forward query */
addr += UNSIGN (block[addr]);
addr += 2; /* skip key */
addr += UNSIGN (block[addr]);
addr++; /* skip data */
if (addr >= offset) { /* look in next block */
if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
data[0] = EOL1;
goto quit; /* no next block */
}
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
addr = 0;
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
}
}
if (addr >= offset) { /* look in next block */
if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
if (getnflag) {
zref[0] = EOL;
merr_raise (ARGER);
}
data[0] = EOL1;
goto quit; /* no next block */
}
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
addr = 0;
}
{
long len;
char key0[256];
i = 0;
while (i <= addr) { /* compute offset complete key */
len = UNSIGN (block[i++]);
len += (j = UNSIGN (block[i++]));
while (j < len) key0[j++] = block[i++];
key0[j] = g_EOL;
k = i; /* save i for getnflag processing */
i += UNSIGN (block[i]);
i++; /* skip data */
}
if (getnflag) {
int ch0;
i = k;
k = UNSIGN (block[i++]);
stcpy0 (data, &block[i], k); /* get value */
data[k] = EOL1; /* append EOL */
j = 0;
while (zref[j] != DELIM && zref[j] != EOL) j++;
if (zref[j] == EOL) zref[j] = DELIM;
nakoffs = j;
j++;
i = 0; /* make this ref $ZR */
while ((ch = UNSIGN (key0[i++])) != g_EOL) {
ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
(ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
(ch >> 1) + SP)); /* '.' or '-' */
if (ch0 == DEL) {
if (((ch = UNSIGN (key0[i++])) >> 1) == DEL) {
ch0 += DEL;
ch = UNSIGN (key0[i++]);
}
ch0 += (ch >> 1);
}
zref[j++] = ch0;
if (j >= 252) {
zref[j] = EOL;
merr_raise (M75);
goto quit;
}
if (ch & 01) {
nakoffs = j;
zref[j++] = DELIM;
}
}
zref[--j] = EOL;
break;
}
else { /* save data value for inspection with $V(111) */
int ch0;
i = addr;
i += UNSIGN (block[i]);
i += 2; /* skip key */
j = UNSIGN (block[i++]);
stcpy0 (g_o_val, &block[i], j); /* get value */
g_o_val[j] = EOL; /* append EOL */
j = 0;
i = 0;
while ((data[j] = zref[j]) != DELIM) {
if (data[j] == EOL1) {
data[j] = '(';
break;
}
j++;
}
data[j++] = '(';
k = 1;
while ((ch = UNSIGN (key0[i++])) != g_EOL) {
int typ;
if (k) {
k = 0;
if ((typ = (ch > SP))) data[j++] = '"';
}
ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
(ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
(ch >> 1) + SP)); /* '.' or '-' */
if (ch0 == DEL) {
if (((ch = UNSIGN (key0[i++])) >> 1) == DEL) {
ch0 += DEL;
ch = UNSIGN (key0[i++]);
}
ch0 += (ch >> 1);
}
data[j] = ch0;
if (j >= 252) {
data[j] = EOL1;
merr_raise (M75);
goto quit;
}
if (data[j++] == '"') data[j++] = '"';
if (ch & 01) {
if (typ) data[j++] = '"';
data[j++] = ',';
k = 1;
}
}
data[j--] = EOL1;
data[j] = ')';
}
}
break;
case kill_sym: /* search and destroy */
killo: /* entry from killone section */
offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
i = 0;
key1[0] = g_EOL;
while (i < addr) { /* compute complete key */
k = UNSIGN (block[i++]);
k += (j = UNSIGN (block[i++]));
while (j < k) key1[j++] = block[i++];
key1[j] = g_EOL;
i += UNSIGN (block[i]);
i++; /* skip data */
}
/* look whether there's something to do at all */
if (found != 2) { /* is it a descendant ? */
char key0[256];
long trxsav;
if (addr >= offset) { /* nothing to kill in that block */
blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]);
if (blknbr == 0) break; /* there is no next block */
/* maybe there's something in the next block ... */
trxsav = trx;
for (;;) {
other = traceblk[--trx];
addr = traceadr[trx];
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
addr += UNSIGN (block[addr]);
addr += (2 + PLEN); /* skip previous entry */
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
traceadr[trx] = addr;
if (addr < offset) break;
traceadr[trx] = 0;
traceblk[trx] = UNSIGN (block[RLPTR]) * 65536 +
UNSIGN (block[RLPTR + 1]) * 256 +
UNSIGN (block[RLPTR + 2]);
}
trx = trxsav;
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
addr = 0;
k = UNSIGN (block[0]);
stcpy0 (key0, &block[2], k);
key0[k] = g_EOL;
}
else { /* get following entry */
stcpy0 (key0, key1, j);
i = addr;
k = UNSIGN (block[i++]);
k += (j = UNSIGN (block[i++]));
while (j < k) key0[j++] = block[i++];
key0[j] = g_EOL;
}
/* is it a descendant? */
i = 0;
while (compactkey[i] == key0[i]) i++;
if (compactkey[i] != g_EOL) break; /* nothing to kill */
}
/* scan this block for all descendants */
{
long begadr, endadr, len;
char key0[256];
stcpy0 (key0, compactkey, (long) keyl);
begadr = endadr = i = addr;
if (action == killone) {
i += UNSIGN (block[i]);
i += 2; /* skip key */
i += UNSIGN (block[i]);
i++; /* skip data */
endadr = i;
}
else {
while (i < offset) {
len = UNSIGN (block[i++]);
k = j = UNSIGN (block[i++]);
if (k >= keyl) {
i += len;
}
else {
len += k;
while (j < len) key0[j++] = block[i++];
key0[j] = g_EOL;
/* k=0; ueberfluessig */
while (compactkey[k] == key0[k]) {
if (compactkey[k] == g_EOL) break;
k++;
}
if (compactkey[k] != g_EOL) break; /* no descendant */
}
i += UNSIGN (block[i]);
i++; /* skip data */
endadr = i;
}
}
kill_again = (endadr == offset && action != killone); /* may be there's more to kill */
if ((begadr == 0) && (endadr == offset)) { /* block becomes empty */
long left,
right;
char block0[BLOCKLEN];
p_empty: /* entry if pointer block goes empty */
left = UNSIGN (block[LLPTR]) * 65536 +
UNSIGN (block[LLPTR + 1]) * 256 +
UNSIGN (block[LLPTR + 2]);
right = UNSIGN (block[RLPTR]) * 65536 +
UNSIGN (block[RLPTR + 1]) * 256 +
UNSIGN (block[RLPTR + 2]);
if (left) {
lseek (filedes, (long) left * (long) (BLOCKLEN), 0);
read (filedes, block0, BLOCKLEN);
block0[RLPTR] = block[RLPTR];
block0[RLPTR + 1] = block[RLPTR + 1];
block0[RLPTR + 2] = block[RLPTR + 2];
lseek (filedes, (long) left * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
}
if (right) {
lseek (filedes, (long) right * (long) (BLOCKLEN), 0);
read (filedes, block0, BLOCKLEN);
block0[LLPTR] = block[LLPTR];
block0[LLPTR + 1] = block[LLPTR + 1];
block0[LLPTR + 2] = block[LLPTR + 2];
lseek (filedes, (long) right * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
}
b_free (filedes, blknbr); /* modify free list */
/* delete pointer */
/**************************/
{
long trxsav;
long freecnt;
trxsav = trx;
blknbr = traceblk[--trx];
addr = traceadr[trx];
lseek (filedes, (long) (blknbr) * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
freecnt = UNSIGN (block[addr]) + 2 + PLEN;
/* delete key */
offset -= freecnt;
if (offset == 0) { /* pointer block went empty */
if (blknbr == ROOT) { /* global went empty */
lseek (filedes, 0L, 0);
/* note : UNIX does not tell other */
block[BTYP] = EMPTY; /* jobs that a file has been unlinked */
/* as long as they keep it open. */
/* so we mark this global as EMPTY */
write (filedes, block, BLOCKLEN);
close (filedes);
unlink (filnam);
if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
olddes[inuse] = 0;
oldfil[inuse][0] = NUL;
usage[inuse] = 0;
return;
}
goto p_empty; /* clear pointer block */
}
block[OFFS] = offset / 256;
block[OFFS + 1] = offset % 256;
stcpy0 (&block[addr], &block[addr + freecnt], (long) (offset - addr));
for (i = offset; i < offset + freecnt; block[i++] = 0);
lseek (filedes, (long) (blknbr) * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
if (addr == 0) { /* update of pointer */
traceadr[trx] = 0;
update (filedes, &block[2], (long) UNSIGN (block[0]));
}
trx = trxsav;
}
if (kill_again) goto k_again;
break;
}
i = begadr;
j = endadr;
while (j < offset) block[i++] = block[j++];
while (i < offset) block[i++] = 0;
/** clear rest */
offset += (begadr - endadr);
if (begadr < offset && block[begadr + 1]) { /* new key_offset for next entry */
i = block[begadr];
j = block[begadr + 1];
k = 0;
if (begadr)
while (key0[k] == key1[k])
k++; /* new key_offset */
if (k < j) {
ch = j - k; /* space requirement */
block[begadr] = i + ch; /* new key_length */
block[begadr + 1] = k; /* new key_offset */
i = offset;
j = i + ch;
offset = j;
begadr++;
while (i > begadr)
block[j--] = block[i--];
stcpy0 (&block[begadr + 1], &key0[k], ch);
}
}
block[OFFS] = offset / 256;
block[OFFS + 1] = offset % 256;
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
if (addr < 3) { /* update of pointer */
traceadr[trx] = 0;
update (filedes, &block[2], (long) UNSIGN (block[0]));
}
}
if (kill_again) goto k_again;
break;
zinv:
{
long len;
int ch0;
char scratch[256];
char key0[256];
if (addr <= 0) { /* look in previous block */
if ((blknbr = UNSIGN (block[LLPTR]) * 65536 + UNSIGN (block[LLPTR + 1]) * 256 + UNSIGN (block[LLPTR + 2])) == 0) {
data[0] = EOL1;
goto quit;
} /* no previous block */
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
addr = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
}
i = 0;
while (i < addr) { /* compute offset complete key */
len = UNSIGN (block[i++]);
len += (j = UNSIGN (block[i++]));
while (j < len) key0[j++] = block[i++];
key0[j] = g_EOL;
j1 = i;
i += UNSIGN (block[i]);
i++; /* skip data */
}
/* save data value for inspection with $V(111) */
j = UNSIGN (block[j1++]);
stcpy0 (g_o_val, &block[j1], j); /* get value */
g_o_val[j] = EOL; /* append EOL */
i = 0;
j = 0;
while ((scratch[j++] = UNSIGN (key0[i++])) != g_EOL);
/* count subscripts of key */
i = 0;
j1 = 0;
while (i < keyl) {
if (compactkey[i++] & 01) {
j1++;
}
}
i = 0;
j = 0;
k = 0;
while (i < keyl) {
if (scratch[i] != compactkey[j++]) {
k++;
break;
}
if (scratch[i++] & 01) k++;
}
if (k < j1) {
data[0] = EOL1;
g_o_val[0] = EOL;
goto quit;
}
while (--i >= 0) {
if ((scratch[i] & 01)) break;
}
i++;
j = 0;
while ((ch = UNSIGN (scratch[i++])) != g_EOL) {
ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
(ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
(ch >> 1) + SP)); /* '.' or '-' */
if (ch0 == DEL) {
if (((ch = UNSIGN (scratch[i++])) >> 1) == DEL) {
ch0 += DEL;
ch = UNSIGN (scratch[i++]);
}
ch0 += (ch >> 1);
}
data[j++] = ch0;
if (ch & 01) break;
}
data[j] = EOL1;
if (j == 0) break;
ordercounter++;
if (ordercnt++ < (-1)) { /* repeated backward scanning */
if (ch != g_EOL) scratch[i] = g_EOL;
stcpy0 (compactkey, scratch, i + 1);
compactkey[i - 1] |= 01;
keyl = i;
goto k_again;
}
}
break;
case zdata: /* nonstandard data function */
{
long counties[128];
char key0[256];
int icnt, icnt0, len;
i = 0;
while (i < 128) counties[i++] = 0L; /* init count; */
if (found == 2) { /* ... advance to next entry */
addr += UNSIGN (block[addr]);
addr += 2; /* skip key */
addr += UNSIGN (block[addr]);
addr++; /* skip data */
counties[0] = 1L;
}
offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
icnt = 0;
i = 0;
while ((ch = compactkey[i++]) != g_EOL) {
if (ch & 01) {
icnt++;
}
}
len = i - 1;
i = 0;
while (i < addr) { /* compute offset complete key */
icnt0 = UNSIGN (block[i++]);
icnt0 += (j = UNSIGN (block[i++]));
while (j < icnt0) key0[j++] = block[i++];
key0[j] = g_EOL;
i += UNSIGN (block[i]);
i++; /* skip data */
}
for (;;) { /* is it still a descendant ??? */
if (addr >= offset) { /* look in next block */
if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
break; /* no next block */
}
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
addr = 0;
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
}
i = UNSIGN (block[addr++]);
i += (j = UNSIGN (block[addr++]));
while (j < i) key0[j++] = block[addr++];
addr += UNSIGN (block[addr]);
addr++; /* skip data */
icnt0 = 0;
i = 0;
while (i < j) if (key0[i++] & 01)
icnt0++;
if (icnt0 <= icnt) break;
i = 0;
while (i < len) {
if (key0[i] != compactkey[i]) break;
i++;
}
if (i < len) break;
counties[icnt0 - icnt]++;
}
i = 128;
while (counties[--i] == 0L);
lintstr (data, counties[0]);
j = 1;
tmp1[0] = ',';
while (j <= i) {
lintstr (&tmp1[1], counties[j++]);
stcat (data, tmp1);
}
}
break;
case getinc:
{
int setopsav;
setopsav = setop;
setop = '+';
data[0] = '1';
data[1] = EOL;
global (set_sym, key, data);
setop = setopsav;
return;
}
case killone:
{
if (found == 2) goto killo; /* entry found use normal kill routine */
goto quit;
}
case merge_sym:
printf("MERGE NOT IMPLEMENTED FOR GLOBALS\n");
#ifdef DEBUG_GBL
int loop;
printf ("DEBUG MERGE: ");
printf ("[key] is [");
for (loop = 0; key[loop] != EOL; loop++) printf ("%c", (key[loop] == DELIM) ? '!' : key[loop]);
printf ("]\r\n");
printf ("[data] is [");
for(loop = 0; data[loop] != EOL; loop++) printf ("%c", (data[loop] == DELIM) ? '!' : data[loop]);
printf("]\r\n");
#endif
return;
default:
merr_raise (INVREF); /* accidental call with wrong action code (v22-stuff) */
} /* end of switch */
quit:
/* clean things up */
lseek (filedes, ROOT, 0);
if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
return;
splitd: /* split data block in two sections */
/* part of the data is taken to an other location. */
/* old information in 'block' stored at 'blknbr' */
/* 'addr' there I would like to insert, if possible (which is not) */
/* 'offset' filled up to this limit */
getnewblk (filedes, &newblk); /* get a new block */
/* if we have to insert at the begin or end of a block */
/* we don't split - we just start a new block */
/* if an insert in the midst of a block, we split */
if (addr >= offset) {
long right,
right1,
right2;
right = UNSIGN (block[RLPTR]);
right1 = UNSIGN (block[RLPTR + 1]);
right2 = UNSIGN (block[RLPTR + 2]);
block[RLPTR] = newblk / 65536;
block[RLPTR + 1] = newblk % 65536 / 256;
block[RLPTR + 2] = newblk % 256;
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
block[RLPTR] = right;
block[RLPTR + 1] = right1;
block[RLPTR + 2] = right2;
block[LLPTR] = blknbr / 65536;
block[LLPTR + 1] = blknbr % 65536 / 256;
block[LLPTR + 2] = blknbr % 256;
offset = 0;
addr = 0;
blknbr = newblk;
insert (filedes, compactkey, keyl, newblk);
/* up-date LL-PTR of RL-block */
if ((other = right * 65536 + right1 * 256 + right2)) {
char block0[BLOCKLEN];
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
read (filedes, block0, BLOCKLEN);
block0[LLPTR] = blknbr / 65536;
block0[LLPTR + 1] = blknbr % 65536 / 256;
block0[LLPTR + 2] = blknbr % 256;
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
}
goto spltex;
}
if (addr == 0) {
long left, left1, left2;
left = UNSIGN (block[LLPTR]);
left1 = UNSIGN (block[LLPTR + 1]);
left2 = UNSIGN (block[LLPTR + 2]);
block[LLPTR] = newblk / 65536;
block[LLPTR + 1] = newblk % 65536 / 256;
block[LLPTR + 2] = newblk % 256;
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
block[LLPTR] = left;
block[LLPTR + 1] = left1;
block[LLPTR + 2] = left2;
block[RLPTR] = blknbr / 65536;
block[RLPTR + 1] = blknbr % 65536 / 256;
block[RLPTR + 2] = blknbr % 256;
offset = 0;
blknbr = newblk;
traceadr[trx] = (-1); /* inhibit second update of pointers */
insert (filedes, compactkey, keyl, newblk);
if (addr < 3) { /* update of pointer */
traceadr[trx] = 0;
update (filedes, compactkey, keyl);
}
/* other is ***always*** zero !!!
* if (other=left*65536+left1*256+left2) up-date RL-PTR of LL-block
* { char block0[BLOCKLEN];
* lseek(filedes,(long)other*(long)(BLOCKLEN),0);
* read(filedes,block0,BLOCKLEN);
* block0[RLPTR ]=blknbr/65536;
* block0[RLPTR+1]=blknbr%65536/256;
* block0[RLPTR+2]=blknbr%256;
* lseek(filedes,(long)other*(long)(BLOCKLEN),0);
* write(filedes,block0,BLOCKLEN);
* }
*/
goto spltex;
}
{
char block0[BLOCKLEN];
char key0[256];
int newlimit;
block0[BTYP] = DATA;
/* now search for a dividing line */
limit = (offset + needed) / 2;
i = (offset - needed) / 2;
if (addr < i) limit = i;
i = 0;
newlimit = i;
while (i < limit) {
newlimit = i;
j = UNSIGN (block[i++]); /* length of key - offset */
k = UNSIGN (block[i++]); /* offset into previous entry */
j += k;
while (k < j) key0[k++] = block[i++]; /* get key */
key0[k] = g_EOL;
i += UNSIGN (block[i]);
i++; /* skip data */
}
limit = newlimit;
i = newlimit;
j = i;
i = 0; /* copy part of old to new blk */
if ((k = UNSIGN (block[j + 1])) != 0) { /* expand key */
block0[i++] = UNSIGN (block[j++]) + k;
block0[i++] = 0;
if (addr > limit) addr += k;
j = 0;
while (j < k) block0[i++] = key0[j++];
j = limit + 2;
}
while (j < offset) {
block0[i++] = block[j];
block[j] = 0;
j++;
}
while (i <= DATALIM) block0[i++] = 0; /* clear rest of block */
offset -= limit;
if (k > 0) offset += k; /* new offsets */
block[OFFS] = limit / 256;
block[OFFS + 1] = limit % 256;
block0[OFFS] = offset / 256;
block0[OFFS + 1] = offset % 256;
if (addr <= limit) { /* save new block away */
/* update rightlink and leftlink pointers */
other = UNSIGN (block[RLPTR]) * 65536 +
UNSIGN (block[RLPTR + 1]) * 256 +
UNSIGN (block[RLPTR + 2]);
block0[RLPTR] = block[RLPTR];
block0[RLPTR + 1] = block[RLPTR + 1];
block0[RLPTR + 2] = block[RLPTR + 2];
block[RLPTR] = newblk / 65536;
block[RLPTR + 1] = newblk % 65536 / 256;
block[RLPTR + 2] = newblk % 256;
block0[LLPTR] = blknbr / 65536;
block0[LLPTR + 1] = blknbr % 65536 / 256;
block0[LLPTR + 2] = blknbr % 256;
lseek (filedes, (long) (newblk) * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
offset = limit;
/* insert new block in pointer structure */
insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
/* up-date LL-PTR of RL-block */
if (other != 0) {
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
read (filedes, block0, BLOCKLEN);
block0[LLPTR] = newblk / 65536;
block0[LLPTR + 1] = newblk % 65536 / 256;
block0[LLPTR + 2] = newblk % 256;
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
}
}
else {
/* save old block away and make new block the current block */
/* update rightlink and leftlink pointers */
other = UNSIGN (block[RLPTR]) * 65536 +
UNSIGN (block[RLPTR + 1]) * 256 +
UNSIGN (block[RLPTR + 2]);
block0[RLPTR] = block[RLPTR];
block0[RLPTR + 1] = block[RLPTR + 1];
block0[RLPTR + 2] = block[RLPTR + 2];
block[RLPTR] = newblk / 65536;
block[RLPTR + 1] = newblk % 65536 / 256;
block[RLPTR + 2] = newblk % 256;
block0[LLPTR] = blknbr / 65536;
block0[LLPTR + 1] = blknbr % 65536 / 256;
block0[LLPTR + 2] = blknbr % 256;
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
stcpy0 (block, block0, (long) BLOCKLEN);
traceadr[trx] = (addr -= limit);
traceblk[trx] = (blknbr = newblk);
/* insert new block in pointer structure */
insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
/* up-date LL-PTR of RL-block */
if (other != 0) {
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
read (filedes, block0, BLOCKLEN);
block0[LLPTR] = newblk / 65536;
block0[LLPTR + 1] = newblk % 65536 / 256;
block0[LLPTR + 2] = newblk % 256;
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
}
}
}
spltex:
if (ret_to == 'n') goto s10;
goto s20;
} /* end global() */
/*
* split pointer block in two sections
* filedes: global file descriptor
* block: old block (which is too small)
* addr: addr of entry where to insert
* offs: offset of block
* blknbr: number of old block
*
* part of the data is taken to an other location.
* old information in 'block' stored at 'blknbr'
* 'addr' there I would like to insert, if possible (which is not)
* 'offset' filled up to this limit
*/
static void splitp (short filedes, char *block, long *addr, long *offs, unsigned long *blknbr)
{
char block0[BLOCKLEN];
long limit;
unsigned long newblk;
unsigned long other;
register int i, j;
getnewblk (filedes, &newblk); /* get a new block */
if (*blknbr == ROOT) { /* ROOT overflow is special */
stcpy0 (block0, block, (long) BLOCKLEN);
/* clear pointers */
block[LLPTR] = 0;
block[LLPTR + 1] = 0;
block[LLPTR + 2] = 0;
block[RLPTR] = 0;
block[RLPTR + 1] = 0;
block[RLPTR + 2] = 0;
/* old root block is a 'normal' block now */
/* new root points to a single block */
i = UNSIGN (block0[0]) + 2;
block0[i++] = newblk / 65536;
block0[i++] = newblk % 65536 / 256;
block0[i++] = newblk % 256;
block0[OFFS] = i / 256;
block0[OFFS + 1] = i % 256;
while (i < DATALIM) block0[i++] = 0; /* clear rest */
/* update number of blocks ! */
i = UNSIGN (block0[NRBLK]) * 65536 +
UNSIGN (block0[NRBLK + 1]) * 256 +
UNSIGN (block0[NRBLK + 2]) + 1;
block0[NRBLK] = i / 65536;
block0[NRBLK + 1] = i % 65536 / 256;
block0[NRBLK + 2] = i % 256;
block0[BTYP] = POINTER;
lseek (filedes, ROOT, 0);
write (filedes, block0, BLOCKLEN);
/* shift trace_stack */
j = trx++;
i = trx;
/** if (j>=TRLIM) 'global too big' */
while (j >= 0) {
traceblk[i] = traceblk[j];
traceadr[i--] = traceadr[j--];
}
traceblk[0] = 0; /*ROOT */
traceadr[0] = 0;
traceblk[1] = newblk;
*blknbr = newblk;
getnewblk (filedes, &newblk); /* get a new block */
}
block0[BTYP] = block[BTYP];
/* now search for a dividing line */
i = 0;
limit = (*offs) / 2;
while (i < limit) {
i += UNSIGN (block[i]);
i += 2; /* skip key */
i += PLEN; /* skip data */
}
/* new offsets */
limit = i;
i = (*offs) - limit;
block[OFFS] = limit / 256;
block[OFFS + 1] = limit % 256;
block0[OFFS] = i / 256;
block0[OFFS + 1] = i % 256;
for (i = 0; i <= DATALIM; block0[i++] = 0);
i = 0;
j = limit; /* copy part of old to new blk */
while (j < (*offs)) {
block0[i++] = block[j];
block[j] = 0;
j++;
}
if ((*addr) <= limit) { /* save new block away */
/* update rightlink and leftlink pointers */
other = UNSIGN (block[RLPTR]) * 65536 +
UNSIGN (block[RLPTR + 1]) * 256 +
UNSIGN (block[RLPTR + 2]);
block0[RLPTR] = block[RLPTR];
block0[RLPTR + 1] = block[RLPTR + 1];
block0[RLPTR + 2] = block[RLPTR + 2];
block[RLPTR] = newblk / 65536;
block[RLPTR + 1] = newblk % 65536 / 256;
block[RLPTR + 2] = newblk % 256;
block0[LLPTR] = (*blknbr) / 65536;
block0[LLPTR + 1] = (*blknbr) % 65536 / 256;
block0[LLPTR + 2] = (*blknbr) % 256;
lseek (filedes, (long) (newblk) * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
(*offs) = limit;
insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
/* up-date LL-PTR of RL-block */
if (other != 0) {
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
read (filedes, block0, BLOCKLEN);
block0[LLPTR] = newblk / 65536;
block0[LLPTR + 1] = newblk % 65536 / 256;
block0[LLPTR + 2] = newblk % 256;
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
}
}
else { /* save old block away and make new block the current block */
/* update rightlink and leftlink pointers */
other = UNSIGN (block[RLPTR]) * 65536 +
UNSIGN (block[RLPTR + 1]) * 256 +
UNSIGN (block[RLPTR + 2]);
block0[RLPTR] = block[RLPTR];
block0[RLPTR + 1] = block[RLPTR + 1];
block0[RLPTR + 2] = block[RLPTR + 2];
block[RLPTR] = newblk / 65536;
block[RLPTR + 1] = newblk % 65536 / 256;
block[RLPTR + 2] = newblk % 256;
block0[LLPTR] = (*blknbr) / 65536;
block0[LLPTR + 1] = (*blknbr) % 65536 / 256;
block0[LLPTR + 2] = (*blknbr) % 256;
(*addr) -= limit;
(*offs) -= limit;
lseek (filedes, (long) (*blknbr) * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
stcpy0 (block, block0, (long) BLOCKLEN);
(*blknbr) = newblk;
insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
/* up-date LL-PTR of RL-block */
if (other != 0) {
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
read (filedes, block0, BLOCKLEN);
block0[LLPTR] = newblk / 65536;
block0[LLPTR + 1] = newblk % 65536 / 256;
block0[LLPTR + 2] = newblk % 256;
lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
write (filedes, block0, BLOCKLEN);
}
}
return;
} /* end of splitp() */
/* update pointer
* filedes: file descriptor
* ins_key: key to be inserted
* keyl: length of that key
*/
static void update (short filedes, char *ins_key, long keyl)
{
long offset;
long addr;
unsigned long blknbr;
char block[BLOCKLEN];
long i, j, k;
while (traceadr[trx] == 0) { /* update of pointer blocks necessary */
if (--trx < 0) break;
blknbr = traceblk[trx];
addr = traceadr[trx];
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
{
long oldkeyl;
oldkeyl = UNSIGN (block[addr]);
i = addr + keyl + 1;
j = oldkeyl - keyl;
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
if (j > 0) { /* surplus space */
k = offset;
offset -= j;
j += i;
while (i < offset) block[i++] = block[j++];
while (i < k) block[i++] = 0; /* clear area */
}
else if (j < 0) { /* we need more space */
/* block too small */
if ((offset - j) > DATALIM) splitp (filedes, block, &addr, &offset, &blknbr);
i = offset;
offset -= j;
j = offset;
k = addr + oldkeyl;
while (i > k) block[j--] = block[i--];
}
block[OFFS] = offset / 256;
block[OFFS + 1] = offset % 256;
block[addr] = keyl;
/* overwrite */
i = 0;
j = (++addr);
block[j++] = 0; /*!!! */
while (i < keyl) block[j++] = ins_key[i++];
/* block pointed to remains the same */
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
}
lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
}
return;
} /* end of update() */
/*
* insert pointer
* filedes: file descriptor
* ins_key: key to be inserted
* key_len: length of that key
* blknbr: key points to this block
*/
static void insert (int filedes, char *ins_key, long key_len, unsigned long blknbr) /* insert pointer */
{
unsigned long blk;
char block[BLOCKLEN];
long trxsav;
long offset;
long needed;
long addr;
register int i, k;
trxsav = trx--;
blk = traceblk[trx];
addr = traceadr[trx];
lseek (filedes, (long) (blk) * (long) (BLOCKLEN), 0);
read (filedes, block, BLOCKLEN);
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
if (traceadr[trx + 1] != (-1)) {
addr += UNSIGN (block[addr]);
addr += (2 + PLEN);
} /* advance to next entry */
needed = key_len + 2 + PLEN;
if ((offset + needed) > DATALIM) splitp (filedes, block, &addr, &offset, &blk);
/* insert key */
i = (offset += needed);
block[OFFS] = i / 256;
block[OFFS + 1] = i % 256;
while (i >= addr) {
block[i] = block[i - needed];
i--;
}
i = addr + 2;
k = 0;
while (k < key_len) block[i++] = ins_key[k++];
block[addr] = k;
block[addr + 1] = 0; /* !!! */
block[i++] = blknbr / 65536;
block[i++] = blknbr % 65536 / 256;
block[i] = blknbr % 256;
lseek (filedes, (long) (blk) * (long) (BLOCKLEN), 0);
write (filedes, block, BLOCKLEN);
trx = trxsav;
return;
} /* end of insert() */
/*
* mark 'blknbr' as free
* filedes: global file descriptor
* blknbr: block to be freed
*/
static void b_free (short filedes, unsigned long blknbr)
{
char block0[BLOCKLEN];
unsigned long free;
unsigned long other;
long i;
long offset;
/* mark block as empty */
lseek (filedes, (long) (blknbr) * BLOCKLEN, 0);
read (filedes, block0, BLOCKLEN);
block0[BTYP] = EMPTY;
lseek (filedes, (long) (blknbr) * BLOCKLEN, 0);
write (filedes, block0, BLOCKLEN);
/* do we have a list of free blocks? */
lseek (filedes, ROOT, 0);
read (filedes, block0, BLOCKLEN);
if ((free = UNSIGN (block0[FREE]) * 65536 + UNSIGN (block0[FREE + 1]) * 256 + UNSIGN (block0[FREE + 2]))) {
for (;;) {
lseek (filedes, (long) free * (long) BLOCKLEN, 0);
read (filedes, block0, BLOCKLEN);
other = UNSIGN (block0[RLPTR]) * 65536 +
UNSIGN (block0[RLPTR + 1]) * 256 +
UNSIGN (block0[RLPTR + 2]);
if (other == 0) break;
free = other;
}
offset = UNSIGN (block0[OFFS]) * 256 + UNSIGN (block0[OFFS + 1]);
/* if list is full, start new page */
if (offset > (DATALIM - PLEN)) {
offset -= PLEN;
other = UNSIGN (block0[offset]) * 65536 +
UNSIGN (block0[offset + 1]) * 256 +
UNSIGN (block0[offset + 2]);
block0[offset] = 0;
block0[offset + 1] = 0;
block0[offset + 2] = 0;
block0[OFFS] = offset / 256;
block0[OFFS + 1] = offset % 256;
block0[RLPTR] = other / 65536;
block0[RLPTR + 1] = other % 65536 / 256;
block0[RLPTR + 2] = other % 256;
lseek (filedes, (long) free * (long) BLOCKLEN, 0);
write (filedes, block0, BLOCKLEN);
for (i = 0; i < BLOCKLEN; block0[i++] = 0); /* clear block */
block0[BTYP] = FBLK;
block0[LLPTR] = free / 65536;
block0[LLPTR + 1] = free % 65536 / 256;
block0[LLPTR + 2] = free % 256;
offset = 0;
free = other;
}
}
else {
getnewblk (filedes, &free);
/* set FBLK free blocks pointer */
lseek (filedes, ROOT, 0);
read (filedes, block0, BLOCKLEN);
block0[FREE] = free / 65536;
block0[FREE + 1] = free % 65536 / 256;
block0[FREE + 2] = free % 256;
lseek (filedes, ROOT, 0);
write (filedes, block0, BLOCKLEN);
for (i = 0; i < BLOCKLEN; block0[i++] = 0); /* clear block */
block0[BTYP] = FBLK;
offset = 0;
}
/* enter 'blknbr' */
block0[offset++] = blknbr / 65536;
block0[offset++] = blknbr % 65536 / 256;
block0[offset++] = blknbr % 256;
block0[OFFS] = offset / 256;
block0[OFFS + 1] = offset % 256;
lseek (filedes, (long) free * (long) BLOCKLEN, 0);
write (filedes, block0, BLOCKLEN);
return;
} /* end of b_free() */
/*
* scan pointer 'block' for 'compactkey'
*
* 'adr' will return an adress
* 2 heureka; key found at adr
* 1 not found, adr=following entry
*/
static void scanpblk (char *block, long *adr, long *fnd)
{
register int i = 0;
register int k;
long j, offset, len;
char key0[256];
*adr = 0;
offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
while (i < offset) {
#ifdef VERSNEW
j = i; /* save adress of current entry */
len = UNSIGN (block[i++]);
stcpy0 (key0, &block[++i], len);
key0[len] = g_EOL;
i += len;
#else
j = i++;
len = UNSIGN (block[j]);
k = 0;
i++;
while (k < len) key0[k++] = block[i++];
key0[k] = g_EOL;
#endif /* VERSNEW */
if (((*fnd) = g_collate (key0)) == 1) return;
*adr = j;
if ((*fnd) == 2) return;
i += PLEN;
}
return;
} /* end of scanpblk() */
/*
* scan 'block' for 'compactkey'
* same stuff as scanpblk for the params.
*/
static void scandblk (char *block, long *adr, long *fnd)
{
register int i = 0;
register int k;
long offset, len;
char key0[256];
offset = UNSIGN (block[OFFS]) * 256 +
UNSIGN (block[OFFS + 1]);
while (i < offset) {
#ifdef VERSNEW
*adr = i;
len = UNSIGN (block[i++]);
k = UNSIGN (block[i++]);
stcpy0 (&key0[k], &block[i], len);
key0[k + len] = g_EOL;
i += len;
#else
*adr = i++;
len = UNSIGN (block[*adr]) + (k = UNSIGN (block[i++]));
while (k < len) key0[k++] = block[i++];
key0[k] = g_EOL;
#endif /* VERSNEW */
if (((*fnd) = g_collate (key0)) != 0) return;
i += UNSIGN (block[i]);
i++; /* skip data */
}
*adr = i;
return;
} /* end of scandblk() */
/*
* get a new block
* filedes: global file descriptor
* blknbr: number of new block
*/
static void getnewblk (int filedes, unsigned long *blknbr)
{
char nblock[BLOCKLEN];
unsigned long freeblks, no_of_blks;
long other;
long offset;
lseek (filedes, ROOT, 0);
read (filedes, nblock, BLOCKLEN);
freeblks = UNSIGN (nblock[FREE]) * 65536 + UNSIGN (nblock[FREE + 1]) * 256 + UNSIGN (nblock[FREE + 2]);
no_of_blks = UNSIGN (nblock[NRBLK]) * 65536 + UNSIGN (nblock[NRBLK + 1]) * 256 + UNSIGN (nblock[NRBLK + 2]);
if (freeblks) {
lseek (filedes, (long) (freeblks) * BLOCKLEN, 0);
read (filedes, nblock, BLOCKLEN);
offset = UNSIGN (nblock[OFFS]) * 256 + UNSIGN (nblock[OFFS + 1]);
if (offset == 0) { /* free list is empty. return free list blk as new block. */
*blknbr = freeblks;
other = UNSIGN (nblock[RLPTR]) * 65536 + UNSIGN (nblock[RLPTR + 1]) * 256 + UNSIGN (nblock[RLPTR + 2]);
/* update RL-block, if any */
if (other) {
lseek (filedes, (long) (other) * BLOCKLEN, 0);
read (filedes, nblock, BLOCKLEN);
nblock[LLPTR] = 0;
nblock[LLPTR + 1] = 0;
nblock[LLPTR + 2] = 0;
lseek (filedes, (long) (other) * BLOCKLEN, 0);
write (filedes, nblock, BLOCKLEN);
}
/* update ROOT block */
lseek (filedes, ROOT, 0);
read (filedes, nblock, BLOCKLEN);
nblock[FREE] = other / 65536;
nblock[FREE + 1] = other % 65536 / 256;
nblock[FREE + 2] = other % 256;
lseek (filedes, ROOT, 0);
write (filedes, nblock, BLOCKLEN);
return;
}
offset -= PLEN;
*blknbr = UNSIGN (nblock[offset]) * 65536 + UNSIGN (nblock[offset + 1]) * 256 + UNSIGN (nblock[offset + 2]);
nblock[offset] = 0;
nblock[offset + 1] = 0;
nblock[OFFS] = offset / 256;
nblock[OFFS + 1] = offset % 256;
lseek (filedes, (long) (freeblks) * BLOCKLEN, 0);
write (filedes, nblock, BLOCKLEN);
return;
}
/* else ** freeblk==0 ** */
no_of_blks++;
nblock[NRBLK] = no_of_blks / 65536;
nblock[NRBLK + 1] = no_of_blks % 65536 / 256;
nblock[NRBLK + 2] = no_of_blks % 256;
lseek (filedes, ROOT, 0);
write (filedes, nblock, BLOCKLEN);
*blknbr = no_of_blks;
for (;;) {
errno = 0;
lseek (filedes, (long) (no_of_blks) * BLOCKLEN, 0);
write (filedes, nblock, BLOCKLEN);
if (errno == 0) break;
panic ();
}
return;
} /* end of getnewblk() */
/*
* return TRUE if 't' follows 'compactkey' in MUMPS collating sequence
*/
static short int g_collate (char *t)
{
char *s = compactkey;
register int chs = *s;
register int cht = *t;
register int tx = 0;
register int sx;
short dif;
/* the empty one is the leader! */
if (chs == g_EOL) {
if (cht == g_EOL) return 2;
return TRUE;
}
if (cht == g_EOL) return FALSE;
while (cht == s[tx]) {
if (cht == g_EOL) return 2;
cht = t[++tx];
} /* (s==t) */
chs = s[tx];
if (chs == OMEGA) return FALSE;
if (chs == ALPHA) return cht != g_EOL;
if (chs == g_EOL && t[tx - 1] & 01) return TRUE;
if (cht == g_EOL && s[tx - 1] & 01) return FALSE;
if (tx > 0) {
tx--;
while ((t[tx] & 01) == 0) {
tx--;
if (tx < 0) break;
}
tx++;
}
chs = s[tx];
cht = t[tx];
if (UNSIGN (chs) <= POINT) { /* then come numerics */
if (UNSIGN (cht) > POINT) return UNSIGN (cht) != g_EOL;
/* both are numeric! now compare numeric values */
if (chs == MINUS) {
if (cht != MINUS) return TRUE;
}
else {
if (cht == MINUS) return FALSE;
}
if (chs == 1 && cht == POINT) return TRUE;
if (cht == 1 && chs == POINT) return FALSE;
dif = sx = tx;
while (s[sx] != POINT) {
if (s[sx++] & 01) break;
}
while (t[tx] != POINT) {
if (t[tx++] & 01) break;
}
if (tx > sx) return cht != MINUS;
if (tx < sx) return cht == MINUS;
tx = dif;
while ((cht >> 1) == (chs >> 1)) {
if (cht & 01) return t[dif] == MINUS;
if (chs & 01) return t[dif] != MINUS;
chs = s[++tx];
cht = t[tx];
}
return (((cht >> 1) > (chs >> 1)) == (t[dif] != MINUS)) && (t[tx] != s[tx]);
}
if (UNSIGN (cht) <= POINT) return FALSE;
while ((dif = (UNSIGN (cht) >> 1) - (UNSIGN (chs) >> 1)) == 0) { /* ASCII collating */
if ((cht & 01) && ((chs & 01) == 0)) return FALSE;
if ((chs & 01) && ((cht & 01) == 0)) return TRUE;
chs = s[++tx];
cht = t[tx];
}
if (chs == g_EOL) return TRUE;
if (cht == g_EOL) return FALSE;
return dif > 0;
} /* end g_collate() */
/*
* test whether 'str' is canonical
*/
//static short int g_numeric (char *str)
short g_numeric (char *str)
{
register int ptr = 0, ch;
register int point = 0;
if (str[0] == '-') {
if ((ch = str[++ptr]) == EOL || (ch == DELIM) || (ch == '0')) return FALSE;
}
else if (str[0] == '0') {
if ((ch = str[ptr + 1]) == EOL || ch == DELIM) return TRUE;
return FALSE; /* leading zero */
}
while ((ch = str[ptr++]) != EOL && ch != DELIM) {
if (ch > '9') return FALSE;
if (ch < '0') {
if (ch != '.') return FALSE;
if (point) return FALSE; /* multiple points */
point = TRUE;
}
}
if (point) {
ch = str[ptr - 2];
if (ch == '0' || ch == '.') return FALSE;
}
return TRUE;
} /* end g_numeric() */
void close_all_globals (void)
{
register int i;
for (i = 0; i < NO_GLOBLS; i++) {
if (oldfil[i][0] != NUL) {
close (olddes[i]);
usage[i] = 0;
olddes[i] = 0;
oldfil[i][0] = NUL;
}
}
return;
} /* end close_all_globals() */
static void panic (void)
{
printf ("\033[s\033[25H\033[5;7mwrite needs more disk space immediately\007");
sleep (1);
printf ("\033[m\007\033[2K\033[u");
/* restore screen 'cause system messed up screen */
#ifdef NOWRITEM
write_m ("\033[4~\201");
#endif /* NOWRITEM */
return;
} /* end panic() */
void gbl_dump_stat(void)
{
register int i;
printf ("FreeM Global Statistics [PID %d]\r\n", pid);
printf ("%-10s%-20s%s\r\n", "USECT", "AGE", "FILE");
printf ("%-10s%-20s%s\r\n", "=====", "===", "====");
for (i = 0; i < NO_GLOBLS; i++) {
printf ("%-10d%-20ld%s\r\n", usage[i], g_ages[i], oldfil[i]);
}
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>