Annotation of freem/src/global_bltin.c, revision 1.24
1.1 snw 1: /*
1.24 ! snw 2: * $Id: global_bltin.c,v 1.7 2025/03/24 04:13:11 snw Exp $
1.1 snw 3: * freem database engine
4: *
5: *
1.3 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.4 snw 8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
1.1 snw 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: *
1.5 snw 26: * $Log: global_bltin.c,v $
1.8 snw 27: * Revision 1.7 2025/03/24 04:13:11 snw
28: * Replace action macro dat with fra_dat to avoid symbol conflict on OS/2
29: *
1.7 snw 30: * Revision 1.6 2025/03/24 01:33:30 snw
31: * Guard declaration of time function in global_bltin.c for portability
32: *
1.6 snw 33: * Revision 1.5 2025/03/22 22:52:24 snw
34: * Add STRLEN_GBL macro to manage global string length
35: *
1.5 snw 36: * Revision 1.4 2025/03/09 19:14:25 snw
37: * First phase of REUSE compliance and header reformat
38: *
1.4 snw 39: *
40: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
41: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 42: **/
43:
44: #include <sys/types.h>
45: #include <sys/stat.h>
46: #include <fcntl.h>
47: #include <unistd.h>
48: #include <string.h>
1.24 ! snw 49:
1.1 snw 50: #include <errno.h>
51:
1.24 ! snw 52:
1.8 snw 53: #include "mpsdef.h"
1.24 ! snw 54:
! 55: static void b_free (short filedes, unsigned long blknbr);
! 56: static void splitp (short filedes, char *block, long *addr, long *offs, unsigned long *blknbr);
! 57: static void update (short filedes, char *ins_key, long keyl);
! 58: static void insert (int filedes, char *ins_key, long key_len, unsigned long blknbr);
1.1 snw 59: static void scanpblk (char *block, long *adr, long *fnd);
60: static void scandblk (char *block, long *adr, long *fnd);
1.24 ! snw 61: static void getnewblk (int filedes, unsigned long *blknbr);
1.1 snw 62: static short int g_collate (char *t);
1.24 ! snw 63: //static short int g_numeric (char *str);
1.1 snw 64: short g_numeric (char *str);
65: void close_all_globals(void);
66: static void panic (void);
67:
1.24 ! snw 68: #define ROOT 0L
! 69:
! 70: /* end of line symbol in global module is 30, which is a code not */
! 71: /* otherwise used in subscripts */
! 72: #define g_EOL 30
! 73:
! 74: #define EOL1 EOL
! 75:
! 76: /* numerics (('.'<<1)&037)==28 ; (('-'<<1)&037)==26; */
! 77: #define POINT 28
! 78: #define MINUS 26
! 79:
! 80: /* ALPHA and OMEGA are dummy subscripts in $order processing */
! 81: /* ALPHA sorts before all other subscripts */
! 82: /* OMEGA sorts after all other subscripts */
! 83: /* e.g. ("abc") -> "abc",OMEGA ; ("abc","") -> "abc",ALPHA */
! 84: #define OMEGA 29
! 85: #define ALPHA 31
! 86:
! 87: /* length of blocks. status bytes defined as offset to blocklength */
! 88: /* BLOCKLEN 1024 is defined in mpsdef0 include file */
! 89: #define DATALIM (BLOCKLEN-11)
! 90: #define LLPTR (BLOCKLEN-10)
! 91: #define NRBLK LLPTR
! 92: #define COLLA (BLOCKLEN- 7)
! 93: #define RLPTR (BLOCKLEN- 6)
! 94: #define FREE RLPTR
! 95: #define BTYP (BLOCKLEN- 3)
! 96: #define OFFS (BLOCKLEN- 2)
! 97:
! 98: /* length of blockpointers in bytes */
! 99: #define PLEN 3
! 100:
! 101: #define EMPTY 0
! 102: #define FBLK 1
! 103: #define POINTER 2
! 104: #define BOTTOM 6
! 105: #define DATA 8
! 106:
1.6 snw 107: #if !defined(__OpenBSD__) && !defined(_AIX) && !defined(__osf__) && !defined(MSDOS) && !defined(__vax__) && !defined(__OS2__)
1.24 ! snw 108: long time ();
1.1 snw 109: #endif
110:
111: /* globals management */
112:
113: /* 0 = set_sym 1 = get_sym */
114: /* 2 = kill_sym 3 = $data */
115: /* 5 = $fra_order */
116: /* 7 = $fra_query */
117: /* */
118: /* 14=killone 13=getnext */
119: /* 16=merge_sym 17=$zdata */
120: /* gvn as ASCII-string */
121:
122: /* returns OK action fulfilled */
123: /* (ierr) UNDEF missing in action */
124: /* NAKED illegal naked reference */
125: /* SBSCR illegal subscript */
126: /* DBDGD data base degradation */
127:
128: /* The data is organized in a B* tree structure on external storage.
129: * For a description of the principles of the algorithms see
130: * Donald E. Knuth "The Art of Computer Programming" vol. 3 p. 478.
131: * This tree structure guarantees fast disk access and is the
132: * canonical way to implement M globals.
133: *
134: * Each M global occupies a separate UNIX file in the directory
135: * specified in the globals_path directive for the current namespace
136: * in /etc/freem.conf. The default namespace on a new installation
137: * of FreeM is called "USER".
138: *
139: * Any global whose name begins with "%" will always be stored in the
140: * SYSTEM namespace, in the directory specified in its "globals_path"
141: * directive in /etc/freem.conf (by default, /var/local/freem/SYSTEM/globals).
142: *
143: * The UNIX file names are the same as the corresponding M global
144: * names; i.e. beginning with an '^'. However it is possible to access
145: * globals in other directories if the path name is specified.
146: * E.g. "S ^/usr/mumps/test=1" does "S ^test=1" in the file /usr/mumps/^test.
147: * If FreeM is started with the -s/--standard switches, it is not possible
148: * to specify a directory. There is a syntactic ambiguity: the '/' character
149: * in the directory name is in conflict with the '/' divide operator. Use
150: * parentheses to make things clear:
151: *
152: * ^/usr/mumps/test/2 ; '/2' is part of the name
153: * (^/usr/mumps/test)/2 ; ambiguity resolved
154: * ^test/2 ; '/2' is a divide operation
155: * ^/usr/mumps/test("ok")/2 ; '/2' is a divide
156: *
157: * To prevent jobs from messing the globals up, access is regulated
158: * with the 'locking' mechanism. (that is different from mumps LOCKs)
159: *
160: * Data is organized in blocks of 1024 bytes (BLOCKLEN) with the following
161: * layout:
162: * byte 0 - 1013 'stuff' 0...DATALIM
163: * organization is:
164: * length of key (minus offset into previous key)
165: * offset into previous key
166: * key (without EOL character)
167: * length of data or two bytes as pointer
168: * data(without EOL character) in pointer blocks
169: *
170: * byte 1014 - 1016 leftlink pointer LLPTR
171: * in root block: number of blocks NRBLK
172: * byte 1017 <reserved>
173: * byte 1017 in root block: type of collating sequence COLLA
174: * LSB=0: numeric(standard) LSB=1: alphabetic
175: * byte 1018 - 1020 rightlink pointer RLPTR
176: * in root block: number of free blocks list FREE
177: * byte 1021 block type BTYP
178: * (2=POINTER,6=BOTTOM LEVEL POINTER,8=DATA)
179: * byte 1022 - 1023 offset OFFS
180: * (pointer to unused part of 'stuff')
181: *
182: * the file is *not* closed on return. since access is regulated by the
183: * locking mechanism, that will not spell trouble.
184: */
1.24 ! snw 185:
1.1 snw 186: void global_bltin (short action, char *key, char *data)
187: {
188:
1.24 ! snw 189: /* these must be static variables */
1.9 snw 190:
1.24 ! snw 191: static short filedes; /* filedescr for global access */
1.1 snw 192: static char filnam[256]; /* name of global/unix file */
193:
194: /* the following vars may be */
195: /* static or dynamic */
1.24 ! snw 196:
1.1 snw 197: static unsigned long blknbr; /* block number */
1.24 ! snw 198: static unsigned long oldblk;
1.1 snw 199: static unsigned long newblk;
200: static unsigned long other;
201: static long j1;
202: static long limit;
203: static short typ; /* block type */
1.24 ! snw 204: static long keyl, /* length of compacted key */
! 205: datal, /* length of data */
! 206: olddatal,
! 207: offset,
! 208: found,
! 209: addr, /* address of key in 'block' */
! 210: needed, /* new bytes needed to ins. stuff */
! 211: ret_to, /* return code */
! 212: kill_again;
1.1 snw 213: static char key1[256];
214: static char tmp1[256]; /* intermediate storage for op= */
215: static char block[BLOCKLEN];
216: static int getnflag; /* flag 1=$ZO-variable 0=$Q-function */
217: static int tryfast; /* try fast access if get_sym on */
1.24 ! snw 218: /* previous global */
! 219:
! 220: struct stat dinf; /* get modification date */
! 221:
! 222: long savj,
! 223: savch; /* saved j and ch for multiple pathes */
! 224: register long int i,
! 225: j,
! 226: k,
! 227: ch;
! 228: long pathscan; /* flag for repeated scan of pathlist setting an undef global */
1.1 snw 229:
230:
231: /* process optional limitations */
232: if (glvnflag.all && key[0] >= '%' && key[0] <= 'z') {
233:
234: if ((i = glvnflag.one[0])) { /* number of significant chars */
1.24 ! snw 235:
1.1 snw 236: j = 0;
237: while ((k = key[j]) != DELIM && k != EOL) {
1.24 ! snw 238:
1.1 snw 239: if (j >= i) {
1.24 ! snw 240:
1.1 snw 241: while ((k = key[++j]) != DELIM && k != EOL);
1.24 ! snw 242:
1.1 snw 243: stcpy (&key[i], &key[j]);
1.24 ! snw 244:
1.1 snw 245: break;
246: }
1.24 ! snw 247:
1.1 snw 248: j++;
1.24 ! snw 249:
1.1 snw 250: }
251: }
252:
253: if (glvnflag.one[1]) { /* upper/lower sensitivity */
1.24 ! snw 254:
1.1 snw 255: j = 0;
1.24 ! snw 256:
1.1 snw 257: while ((k = key[j]) != DELIM && k != EOL) {
1.24 ! snw 258:
1.1 snw 259: if (k >= 'a' && k <= 'z') key[j] = k - 32;
1.24 ! snw 260:
1.1 snw 261: j++;
1.24 ! snw 262:
1.1 snw 263: }
264:
265: }
266:
267: if ((i = glvnflag.one[2])) {
1.24 ! snw 268:
1.1 snw 269: if (stlen (key) > i) {
270: merr_raise (M75);
271: return;
272: } /* key length limit */
1.24 ! snw 273:
1.1 snw 274: }
275:
276: if ((i = glvnflag.one[3])) { /* subscript length limit */
1.24 ! snw 277:
1.1 snw 278: j = 0;
1.24 ! snw 279:
1.1 snw 280: while ((k = key[j++]) != DELIM && k != EOL);
1.24 ! snw 281:
1.1 snw 282: if (k == DELIM) {
1.24 ! snw 283:
1.1 snw 284: k = 0;
285: for (;;) {
1.24 ! snw 286:
1.1 snw 287: k = key[j++];
1.24 ! snw 288:
1.1 snw 289: if (k == DELIM || k == EOL) {
1.24 ! snw 290:
1.1 snw 291: if (k > i) {
292: merr_raise (M75);
293: return;
294: }
1.24 ! snw 295:
1.1 snw 296: k = 0;
297: }
1.24 ! snw 298:
1.1 snw 299: if (k == EOL) break;
300:
301: k++;
302: }
303: }
304: }
305: }
306:
1.24 ! snw 307: if (action == getnext) {
1.8 snw 308:
1.1 snw 309: getnflag = TRUE;
310: varnam[0] = EOL;
311:
312: if (zref[0] == EOL) {
313: merr_raise (M7);
314: data[0] = EOL;
315:
316: return;
317: }
318:
319: stcpy (key, zref);
320:
321: action = fra_query;
322: ordercnt = 1L;
323: }
324: else {
325:
326: getnflag = FALSE;
327:
328: /* naked reference section */
329:
330: if (key[1] == DELIM) { /* resolve naked reference */
331:
332: while (--nakoffs >= 0) { /* naked reference pointer */
333: if (zref[nakoffs] == DELIM) break;
334: }
335:
336: if ((i = ++nakoffs) == 0) { /* illegal naked reference */
337: data[0] = EOL1;
338: merr_raise (NAKED);
339:
340: return;
341: }
342:
343: j = 2;
344: while ((zref[i] = key[j++]) != EOL) {
345:
346: if ((++i) >= STRLEN) {
347: zref[255] = EOL;
348: merr_raise (M75);
349:
350: return;
351: }
352:
353: }
354: nakoffs = stcpy (key, zref);
355: }
356: else {
357:
358: /* only save off $REFERENCE if the global isn't part of SSVN backing storage */
359: if (key[1] != '$') {
360: nakoffs = stcpy (zref, key); /* save reference */
361: }
362:
363: }
364: }
365:
1.24 ! snw 366: if (v22ptr) {
! 367:
! 368: procv22 (key);
! 369:
! 370: if (key[0] != '^') {
! 371: char losav[256];
! 372:
! 373: stcpy (losav, l_o_val);
! 374: symtab (action, key, data);
! 375: stcpy (g_o_val, l_o_val);
! 376: stcpy (l_o_val, losav);
! 377:
! 378: return;
! 379: }
! 380: }
! 381:
! 382: /* construct full UNIX filename */
! 383: savj = 0;
! 384: savch = ch = EOL;
! 385: pathscan = TRUE;
! 386: nextpath:
! 387: k = 0;
! 388: j = savj;
! 389:
! 390: if (key[1] == '%' || key[1] == '$') { /* %-globals and SSVN backing storage, no explicit path */
! 391:
! 392: if (gloplib[0] != EOL) {
! 393:
! 394: /* append % global access path */
! 395: while ((ch = filnam[k++] = gloplib[j++]) != ':' && ch != EOL);
! 396:
! 397: }
! 398:
! 399: }
! 400: else if (key[1] != '/') { /* no explicit path specified */
1.1 snw 401:
1.24 ! snw 402: if (glopath[0] != EOL) {
! 403:
! 404: /* append global access path */
! 405: while ((ch = filnam[k++] = glopath[j++]) != ':' && ch != EOL);
! 406:
! 407: }
! 408:
! 409: }
! 410:
! 411: if (savj == 0 && ch == EOL) pathscan = FALSE; /* one path only: inhibit search */
! 412:
! 413: if (k > 0) {
! 414:
! 415: if (k == 1 || (k == 2 && filnam[0] == '.')) {
! 416: k = 0;
! 417: }
! 418: else {
! 419: filnam[k - 1] = '/';
! 420: }
! 421:
! 422: }
! 423:
! 424: savch = ch;
! 425: savj = j;
! 426: i = 0;
! 427: j = 0;
! 428:
! 429: while (key[i] != EOL) {
! 430:
! 431: if ((filnam[k] = key[i]) == DELIM) break;
! 432:
! 433: if (filnam[k] == '/') {
! 434:
! 435: j = i;
! 436:
! 437: if (k > i) {
! 438: i = 0;
! 439: j = 0;
! 440: k = 0;
! 441:
! 442: continue;
! 443: }
! 444:
! 445: }
! 446:
! 447: i++;
! 448: k++;
! 449:
! 450: }
! 451:
! 452: filnam[k] = NUL; /* NUL not EOL !!! */
! 453:
! 454: /* if a unix directory is specified, reposition '^' */
! 455: /* '^/usr/test' becomes '/usr/^test' */
! 456: if (j > 0) {
! 457:
! 458: for (k = 0; k < j; k++) {
! 459: filnam[k] = filnam[k + 1];
! 460: }
! 461:
! 462: filnam[j] = '^';
! 463:
! 464: }
! 465:
1.1 snw 466: /* compact key to internal format: characters are shifted left */
467: /* delimiters become LSB of previous character */
468: /* test subscripts for being numeric or not */
469: /* numeric values are shifted into the code space */
470: /* that is available because of illegal CTRL subscipts */
471:
472: k = 0;
473:
474: if (key[i] == EOL) { /* unsubscripted variable */
475:
476: if (action == fra_order) {
477: g_o_val[0] = EOL;
478: merr_raise (NEXTER);
479:
480: return;
481: }
482:
483: }
484: else if (key[++i] == EOL) { /* empty (first) subscript */
485:
486: if ((action != fra_order) && (action != fra_query)) {
487: merr_raise (SBSCR);
488: return;
489: }
490:
491: }
492: else { /* non empty subscript */
493:
494: j1 = g_numeric (&key[i]);
495:
496: while ((ch = key[i++]) != EOL) {
497:
498: if (ch == DELIM) {
499:
500: if (k == 0) {
501: merr_raise (SBSCR);
502: return;
503: }
504:
505: if (compactkey[--k] & 01) {
506: merr_raise (SBSCR);
507: return;
508: }
509:
510: compactkey[k++] |= 01;
511: j1 = g_numeric (&key[i]);
512:
513: }
514: else if (UNSIGN (ch) >= DEL) { /* transform 8bit char to 7bit */
515:
516: compactkey[k++] = (DEL << 1);
517: ch = UNSIGN (ch) - DEL;
518:
519: if (UNSIGN (ch) >= DEL) {
520: compactkey[k++] = (DEL << 1);
521: ch = UNSIGN (ch) - DEL;
522: }
523:
524: compactkey[k++] = ch << 1;
525:
526: }
1.24 ! snw 527: else if (ch < SP || ch >= DEL) {
! 528:
! 529: /*no CTRLs */
! 530:
1.1 snw 531: merr_raise (SBSCR);
532: return;
533: }
534: else {
535: compactkey[k++] = (j1 ? (ch << 1) & 036 : ch << 1);
536: }
537: }
538:
539: }
540:
541: if (action == fra_order) {
542:
543: if (ordercnt > 0) {
544:
545: compactkey[k] = (k == 0 || (compactkey[k - 1] & 01) ? ALPHA : OMEGA);
546:
547: if (k > 0) compactkey[k - 1] |= 01;
548:
549: keyl = (++k);
550:
551: }
552: else if (ordercnt == 0) { /* no scan at all */
553:
554: k = 0;
555: i = 0;
556:
557: while ((ch = key[i++]) != EOL) {
558: if (ch == DELIM) k = i;
559: }
560:
561: stcpy (data, &key[k]);
562: g_o_val[0] = EOL;
563:
564: return;
565:
566: }
567: else { /* backward scanning */
568:
569: if (k == 0 || (compactkey[k - 1] & 01)) {
570:
571: compactkey[k] = OMEGA;
572:
573: if (k > 0) compactkey[k - 1] |= 01;
574:
575: k++;
576:
577: }
578: else {
579: compactkey[k - 1] |= 01;
580: }
581:
582: keyl = k;
583: }
584:
585: }
586: else {
587:
588: if ((keyl = k) > 0) {
589:
590: if ((compactkey[--k] & 01) && (action != fra_query)) {
591: merr_raise (SBSCR);
592: return;
593: }
594:
595: compactkey[k++] |= 01;
596: }
597: }
598:
599: compactkey[k] = g_EOL;
600:
1.24 ! snw 601: /* look whether file is already open */
! 602: tryfast = FALSE;
! 603: ch = usage[i = j = inuse];
! 604:
! 605: while (i < NO_GLOBLS) {
! 606:
! 607: k = 0;
! 608:
! 609: while (filnam[k] == oldfil[i][k]) {
! 610:
! 611: if (filnam[k++] == NUL) {
! 612:
! 613: filedes = olddes[i];
! 614:
! 615: if (inuse == i && action == get_sym) {
! 616:
! 617: tryfast = TRUE;
! 618:
! 619: if (usage[i] != (-1)) usage[i]++;
! 620: if (lonelyflag) goto tfast2;
! 621:
! 622: fstat (filedes, &dinf);
! 623:
! 624: if (g_ages[i] > dinf.st_mtime) goto tfast2;
! 625:
! 626: g_ages[i] = time (0L);
! 627:
! 628: goto tfast0;
! 629:
! 630: }
! 631:
! 632: inuse = i;
! 633:
! 634: if (usage[i] != (-1)) usage[i]++;
! 635:
! 636: goto lock;
! 637: }
! 638:
! 639: }
! 640:
! 641: if (ch < 0 || (usage[i] >= 0 && usage[i] < ch)) ch = usage[j = i];
! 642:
! 643: if (i++ == inuse) {
! 644: inuse = (-1);
! 645: i = 0;
! 646: }
! 647:
! 648: }
! 649:
! 650: inuse = j;
! 651: usage[j] = 1;
! 652:
! 653: /* close previous file */
! 654: if ((filedes = olddes[j]) > 0) {
! 655: close (filedes);
! 656: olddes[j] = 0;
! 657: }
! 658:
! 659: strcpy (oldfil[j], filnam); /* save current filename */
! 660:
1.1 snw 661: reopen:
662:
1.24 ! snw 663: for (;;) {
! 664:
! 665: errno = 0;
! 666:
! 667: if ((filedes = open (filnam, 2)) != -1) break;
! 668: if (errno == EINTR) continue;
! 669:
! 670: if (errno == EMFILE || errno == ENFILE) { /* too many open files now */
! 671: close_all_globals ();
! 672:
! 673: continue;
! 674: }
! 675:
! 676: break;
! 677: }
! 678:
! 679: if (filedes == -1) {
1.1 snw 680:
1.24 ! snw 681: usage[inuse] = 0;
! 682: oldfil[inuse][0] = NUL;
! 683: olddes[inuse] = 0;
! 684: g_ages[inuse] = 0;
! 685:
! 686: if ((pathscan || errno != ENOENT) && (savch != EOL)) goto nextpath; /* try next access path */
! 687:
1.1 snw 688: /* file not found */
689: if (action != set_sym) {
690:
691: if (errno != ENOENT) {
692: merr_raise (PROTECT);
693: return;
694: }
695:
1.7 snw 696: if (action == fra_dat || action == zdata) {
1.1 snw 697: data[0] = '0';
698: data[1] = EOL1;
699:
700: return;
701: }
702:
703: data[0] = EOL1;
704:
705: if (action == get_sym || getnflag) {
706: merr_raise (M7);
707: data[0] = EOL;
708: }
709: else if (action == fra_order || action == fra_query) {
710: g_o_val[0] = EOL;
711: }
712:
713: return;
714: }
715:
716: if (errno != ENOENT) {
717: merr_raise (PROTECT);
718: return;
719: }
1.24 ! snw 720:
! 721: if (pathscan) {
! 722: savj = 0;
! 723: savch = ch = EOL;
! 724: pathscan = FALSE;
! 725:
! 726: goto nextpath;
! 727: }
! 728:
1.1 snw 729: if (setop) {
730:
731: tmp1[0] = EOL;
732: m_op (tmp1, data, setop);
733: setop = 0;
734:
735: if (merr () > OK) return;
736:
737: datal = stcpy (data, tmp1);
738: }
739:
740: for (i = 0; i < BLOCKLEN; block[i++] = 0); /* clear block */
741:
742: stcpy0 (&block[2], compactkey, (long) keyl);
743:
744: block[0] = keyl; /* $length of key */
745: j = i = keyl + 2;
746: block[i++] = 0;
747: block[i++] = 0;
748: block[i++] = ROOT + 1; /* block 1 = data */
749: block[BTYP] = BOTTOM;
750: block[COLLA] = 0; /* collating sequence */
751: block[OFFS] = i / 256;
752: block[OFFS + 1] = i % 256;
753: block[NRBLK] = 0;
754: block[NRBLK + 1] = 0;
755: block[NRBLK + 2] = ROOT + 1; /* nr. of blocks */
756:
757: /* create file, write_lock it and initialize root block */
1.24 ! snw 758: for (;;) {
1.1 snw 759:
1.24 ! snw 760: errno = 0;
! 761:
! 762: if ((filedes = creat (filnam, 0666)) != -1) break;
! 763:
! 764: if (errno == EMFILE || errno == ENFILE) {
! 765: close_all_globals ();
! 766: continue;
! 767: }
! 768:
! 769: merr_raise (PROTECT);
1.1 snw 770: return;
1.24 ! snw 771: }
1.17 snw 772:
1.24 ! snw 773: if (lonelyflag == FALSE) locking (filedes, 1, 0L);
! 774:
! 775: for (;;) {
! 776:
! 777: errno = 0;
! 778:
! 779: lseek (filedes, ROOT * BLOCKLEN, 0);
! 780: write (filedes, block, BLOCKLEN);
1.1 snw 781:
1.24 ! snw 782: if (errno == 0) break;
! 783:
! 784: panic ();
! 785: }
! 786:
1.1 snw 787: block[NRBLK] = 0;
788: block[NRBLK + 1] = 0;
789: block[NRBLK + 2] = ROOT; /* clear */
790:
791: /* copy and write length of data */
792: block[j] = k = stcpy (&block[j + 1], data);
793: block[i = k + j + 1] = 0; /* clear EOL symbol */
794: block[BTYP] = DATA; /* type */
795: block[OFFS] = i / 256;
796: block[OFFS + 1] = i % 256;
1.24 ! snw 797:
! 798: for (;;) {
! 799:
! 800: errno = 0;
! 801: write (filedes, block, BLOCKLEN);
! 802:
! 803: if (errno == 0) break;
! 804:
! 805: lseek (filedes, (ROOT + 1L) * BLOCKLEN, 0);
! 806: panic ();
1.22 snw 807:
1.24 ! snw 808: }
! 809:
! 810: close (filedes);
! 811:
! 812: if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
1.1 snw 813:
814: /* close new file, so other users can find it */
815: return;
816: }
817:
1.24 ! snw 818: olddes[inuse] = filedes; /* save current filedescriptor */
! 819:
1.1 snw 820: /* request global for exclusive use */
821: /* odd numbered actions get read access (get_sym,data,fra_order) 3 */
822: /* even ones read/write access (set_sym,kill_sym) 1 */
823:
1.24 ! snw 824: lock:
1.1 snw 825:
826: if (action == get_sym) {
827:
1.20 snw 828: tfast0:
1.24 ! snw 829:
! 830: if (lonelyflag == FALSE) locking (filedes, 3, 0L);
! 831: if (tryfast) goto tfast1; /* try again last block */
1.1 snw 832:
1.24 ! snw 833: blknbr = oldblk = ROOT; /* start with ROOT block */
1.1 snw 834:
835: for (;;) {
836:
837:
1.24 ! snw 838: tfast1:
! 839:
! 840: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 841: read (filedes, block, BLOCKLEN);
! 842:
! 843:
! 844: tfast2:
! 845:
! 846: if ((typ = block[BTYP]) == DATA) { /* scan data block: here we test for equality only */
! 847:
! 848: offset = UNSIGN (block[OFFS]) * 256 +
! 849: UNSIGN (block[OFFS + 1]);
! 850: j = UNSIGN (block[0]);
! 851: i = 0;
! 852:
! 853: stcpy0 (key1, &block[2], j); /* get first key */
! 854:
! 855: ch = keyl; /* ch is a register! */
! 856:
! 857: while (i < offset) {
! 858:
! 859: j = UNSIGN (block[i++]); /* length of key - offset */
! 860: k = UNSIGN (block[i++]); /* offset into previous entry */
! 861:
! 862: #ifdef VERSNEW
! 863:
! 864: stcpy0 (&key0[k], &block[i], j);
! 865: i += j;
! 866: j += k;
! 867:
! 868: #else
! 869:
! 870: j += k;
1.1 snw 871:
1.24 ! snw 872: while (k < j) key1[k++] = block[i++]; /* get key */
! 873:
! 874: #endif /* VERSNEW */
! 875:
! 876: if (j != ch) { /* keys have different length */
1.1 snw 877:
878: i += UNSIGN (block[i]);
1.24 ! snw 879: i++;
! 880:
! 881: continue;
! 882:
1.1 snw 883: }
884:
1.24 ! snw 885: /* key1[j]=g_EOL; */
! 886: j = ch;
1.1 snw 887:
1.24 ! snw 888: do {
! 889: j--;
! 890: } while (compactkey[j] == key1[j]); /* compare keys */
1.17 snw 891:
1.24 ! snw 892:
! 893: if (j < 0) {
1.17 snw 894:
1.24 ! snw 895: k = UNSIGN (block[i++]);
! 896: stcpy0 (data, &block[i], k); /* get value */
! 897: data[k] = EOL1; /* append EOL */
! 898:
1.1 snw 899: goto quit;
1.24 ! snw 900:
1.1 snw 901: }
1.24 ! snw 902:
! 903: i += UNSIGN (block[i]);
! 904: i++; /* skip data */
! 905:
! 906: }
! 907:
! 908: /* fast access failed. try normal path */
! 909: if (tryfast) {
! 910: tryfast = FALSE;
! 911: goto tfast0;
1.1 snw 912: }
1.24 ! snw 913:
! 914: merr_raise (M7);
! 915: data[0] = EOL;
1.1 snw 916:
1.24 ! snw 917: goto quit; /* variable not found */
! 918: }
! 919: else {
! 920:
! 921: if (tryfast) {
! 922: tryfast = FALSE;
! 923: goto tfast0;
! 924: }
! 925:
! 926: if (typ == EMPTY) {
! 927:
! 928: if (blknbr == ROOT) {
! 929: close (filedes);
! 930: goto reopen;
! 931: }
! 932:
1.19 snw 933: merr_raise (DBDGD);
934: goto quit;
1.24 ! snw 935:
1.19 snw 936: }
1.1 snw 937:
1.24 ! snw 938: }
! 939:
! 940: scanpblk (block, &addr, &found);
! 941:
! 942: addr += UNSIGN (block[addr]) + 2; /* skip key */
! 943:
! 944: if ((blknbr = UNSIGN (block[addr]) * 65536 + UNSIGN (block[addr + 1]) * 256 + UNSIGN (block[addr + 2])) == oldblk) {
! 945: merr_raise (DBDGD);
! 946: goto quit;
! 947: }
! 948:
! 949: addr += PLEN; /* skip data */
! 950: oldblk = blknbr;
1.1 snw 951:
1.24 ! snw 952: if (merr () == INRPT) goto quit;
1.1 snw 953:
954: }
955: } /* end of get_sym */
956:
1.24 ! snw 957:
! 958: if (lonelyflag == FALSE) locking (filedes, (action & 01 ? 3 : 1), 0L);
! 959:
1.1 snw 960: /* a KILL on an unsubscripted global deletes the entire file */
961: if (action == kill_sym && compactkey[0] == g_EOL) {
962:
1.24 ! snw 963: lseek (filedes, ROOT, 0);
! 964:
! 965: /* note : UNIX does not tell other */
! 966: block[BTYP] = EMPTY; /* jobs that a file has been unlinked */
! 967:
1.1 snw 968: /* as long as they keep it open. */
969: /* so we mark this global as EMPTY */
1.24 ! snw 970: write (filedes, block, BLOCKLEN);
! 971:
! 972: if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
! 973:
! 974: close (filedes);
! 975:
! 976: olddes[inuse] = 0;
! 977: oldfil[inuse][0] = NUL;
! 978: usage[inuse] = 0;
1.1 snw 979:
980: unlink (filnam);
981:
982: return;
983: }
984:
985: k_again: /* entry point for repeated kill operations */
986:
987: /* scan tree for the proper position of key */
1.24 ! snw 988: blknbr = oldblk = ROOT; /* start with ROOT block */
1.1 snw 989: trx = (-1);
990:
991: for (;;) {
992:
993: if (++trx >= TRLIM) {
994: merr_raise (STKOV);
995: goto quit;
996: }
997:
998: traceblk[trx] = blknbr;
999: traceadr[trx] = 0;
1.24 ! snw 1000:
! 1001: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1002: read (filedes, block, BLOCKLEN);
! 1003:
1.1 snw 1004: typ = block[BTYP];
1005:
1006: if (typ == DATA) {
1007: scandblk (block, &addr, &found);
1008: break;
1009: }
1010:
1011: if (typ == EMPTY) {
1012:
1013: if (blknbr == ROOT) {
1.24 ! snw 1014: close (filedes);
1.1 snw 1015: goto reopen;
1016: }
1017:
1018: merr_raise (DBDGD);
1019: goto quit;
1020: }
1021:
1022: scanpblk (block, &addr, &found);
1023:
1024: traceadr[trx] = addr;
1025: addr += UNSIGN (block[addr]);
1026: addr += 2; /* skip key */
1027:
1.24 ! snw 1028: if ((blknbr = UNSIGN (block[addr]) * 65536 + UNSIGN (block[addr + 1]) * 256 + UNSIGN (block[addr + 2])) == oldblk) {
1.1 snw 1029: merr_raise (DBDGD);
1030: goto quit;
1031: }
1032:
1033: addr += PLEN; /* skip data */
1.24 ! snw 1034: oldblk = blknbr;
1.1 snw 1035: }
1036:
1037: traceadr[trx] = addr;
1038:
1039: switch (action) {
1040:
1041: case set_sym:
1042:
1043: datal = stlen (data);
1044: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 1045: UNSIGN (block[OFFS + 1]);
1.1 snw 1046:
1047: if (found != 2) { /* new entry */
1048:
1049: if (setop) {
1050:
1051: tmp1[0] = EOL;
1052:
1053: m_op (tmp1, data, setop);
1054:
1055: setop = 0;
1056:
1057: if (merr () > OK) return;
1058:
1059: datal = stcpy (data, tmp1);
1060:
1061: }
1062:
1063: needed = keyl + datal + 3;
1064:
1065: if ((offset + needed) > DATALIM) {
1066: ret_to = 'n'; /* n=new */
1067: goto splitd;
1068: }
1069:
1070:
1.24 ! snw 1071: s10: {
1.1 snw 1072: long len; /* insert key */
1073: char key0[256];
1074:
1075: i = 0;
1076:
1077: while (i < addr) { /* compute offset into previous entry */
1078:
1079: len = UNSIGN (block[i++]);
1080:
1081: #ifdef VERSNEW
1082:
1083: k = UNSIGN (block[i++]);
1084: stcpy0 (&key0[k], &block[i], len);
1085:
1086: i += len;
1087: key0[k + len] = g_EOL;
1088:
1089: #else
1090:
1091: len += (k = UNSIGN (block[i++]));
1092:
1093: while (k < len) key0[k++] = block[i++];
1094:
1095: key0[k] = g_EOL;
1096:
1097: #endif /* VERSNEW */
1098:
1099: i += UNSIGN (block[i]);
1100: i++; /* skip data */
1101:
1102: }
1103:
1104: k = 0;
1105:
1106: if (addr > 0) {
1107:
1108: while (compactkey[k] == key0[k]) {
1109:
1110: if (key[k] == g_EOL) break;
1111:
1112: k++;
1113:
1114: }
1115:
1116: /* do *not* fully compact numerics */
1117: if ((i = UNSIGN (compactkey[k])) <= POINT) {
1118:
1119: while (--k >= 0 && (UNSIGN (compactkey[k]) & 01) == 0);
1120:
1121: k++;
1122: }
1123:
1124: }
1125:
1126: needed -= k;
1127: i = (offset += needed);
1128: block[OFFS] = i / 256;
1129: block[OFFS + 1] = i % 256;
1130:
1131: while (i >= addr) {
1132: block[i] = block[i - needed];
1133: i--;
1134: }
1135:
1136: #ifdef VERSNEW
1137:
1138: i = addr;
1139: block[i++] = j1 = keyl - k;
1140: block[i++] = k;
1141:
1142: stcpy0 (&block[i], &compactkey[k], j1);
1143:
1144: i += j1;
1145: block[i++] = datal;
1146:
1147: stcpy0 (&block[i], data, datal);
1148:
1149: #else
1150:
1151: block[addr + 1] = k;
1152: j1 = k;
1153: i = addr + 2;
1154:
1155: while (k < keyl) block[i++] = compactkey[k++];
1156:
1157: block[addr] = k - j1;
1158: addr = i++;
1159: k = 0;
1160:
1161: while (k < datal) block[i++] = data[k++];
1162:
1163: block[addr] = k;
1164:
1165: #endif /* VERSNEW */
1166:
1167: }
1168:
1.24 ! snw 1169: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1170: write (filedes, block, BLOCKLEN);
1.1 snw 1171:
1.24 ! snw 1172: if (traceadr[trx] == 0) update (filedes, compactkey, keyl);
1.1 snw 1173:
1174: break;
1175: }
1176:
1177: /* there was a previous entry */
1178: addr += UNSIGN (block[addr]);
1179: addr += 2;
1180: olddatal = UNSIGN (block[addr]);
1181:
1182: if (setop) {
1183:
1184: stcpy0 (tmp1, &block[addr + 1], (long) olddatal);
1185:
1186: tmp1[olddatal] = EOL;
1187:
1188: m_op (tmp1, data, setop);
1189:
1190: setop = 0;
1191:
1192: if (merr () > OK) return;
1193:
1194: datal = stcpy (data, tmp1);
1195: }
1196:
1197: if ((j1 = olddatal - datal) != 0) {
1198:
1199: if (j1 > 0) { /* surplus space */
1200:
1201: i = addr + datal;
1202: k = offset;
1203: offset -= j1;
1204: j1 += i;
1205:
1206: stcpy0 (&block[i], &block[j1], offset - i);
1207:
1208: i = offset;
1209:
1210: while (i < k) block[i++] = 0; /* clear area */
1211:
1212: }
1213: else {
1.24 ! snw 1214: /* if (j1<0) */
1.1 snw 1215: /* we need more space */
1216:
1217: if ((offset - j1) > DATALIM) {
1218: /* block too small */
1219: ret_to = 'u'; /* u=update */
1220:
1221: goto splitd;
1222: }
1223:
1.24 ! snw 1224: s20:
1.1 snw 1225:
1226: i = offset;
1227: k = addr + olddatal;
1228: offset -= j1;
1229: j1 = offset;
1230:
1231: while (i > k) block[j1--] = block[i--];
1232:
1233: }
1234:
1235: /* overwrite */
1236: block[OFFS] = offset / 256;
1237: block[OFFS + 1] = offset % 256;
1238: block[addr] = datal;
1239:
1240: }
1241: else { /* if nothing changes, do not write */
1242:
1243: i = 0;
1244: j = addr + 1;
1245:
1246: while (i < datal) {
1247: if (block[j++] != data[i]) break;
1248:
1249: i++;
1250: }
1251:
1252: if (i == datal) goto quit;
1253:
1254: }
1255:
1256: stcpy0 (&block[++addr], data, (long) datal);
1.24 ! snw 1257: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1258: write (filedes, block, BLOCKLEN);
1.1 snw 1259: break;
1260:
1261:
1.7 snw 1262: case fra_dat:
1.1 snw 1263:
1264: data[0] = '0';
1265: data[1] = EOL1;
1266: data[2] = EOL1;
1267:
1268: if (found == 2) { /* ... advance to next entry */
1269: addr += UNSIGN (block[addr]);
1270: addr += 2; /* skip key */
1271: addr += UNSIGN (block[addr]);
1272: addr++; /* skip data */
1273:
1274: data[0] = '1';
1275: }
1276:
1277: {
1278: long len;
1279: char key0[256];
1280:
1281: /* get following entry, eventually in the next blk */
1282: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 1283: UNSIGN (block[OFFS + 1]);
1.1 snw 1284:
1285: if (addr >= offset) {
1286:
1287: if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]))) {
1.24 ! snw 1288:
! 1289: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1290: read (filedes, block, BLOCKLEN);
1.1 snw 1291: j1 = UNSIGN (block[0]);
1292:
1293: i = 0;
1294: j = 2;
1295:
1296: while (i < j1) key0[i++] = block[j++];
1297:
1298: key0[i] = g_EOL;
1299:
1300: }
1301: else {
1302: goto quit;
1303: }
1304:
1305: }
1306: else {
1307:
1308: i = 0;
1309:
1310: while (i <= addr) { /* compute offset complete key */
1311: len = UNSIGN (block[i++]);
1312:
1313: #ifdef VERSNEW
1314:
1315: k = UNSIGN (block[i++]);
1316: stcpy0 (&key0[k], &block[i], len);
1317: key0[k + len] = g_EOL;
1318: i += len;
1319:
1320: #else
1321:
1322: len += (j = UNSIGN (block[i++]));
1323:
1324: while (j < len) key0[j++] = block[i++];
1325:
1326: key0[j] = g_EOL;
1327:
1328: #endif /* VERSNEW */
1329:
1330: i += UNSIGN (block[i]);
1331: i++; /* skip data */
1332: }
1333:
1334: }
1335:
1336: /* is it a descendant? */
1337: if (compactkey[0] == g_EOL && key0[0] != g_EOL) {
1338: data[1] = data[0];
1339: data[0] = '1';
1340:
1341: break;
1342: }
1343:
1344: i = 0;
1345:
1346: while (compactkey[i] == key0[i]) i++;
1347:
1348: if (compactkey[i] == g_EOL) {
1349: data[1] = data[0];
1350: data[0] = '1';
1351: }
1352: }
1353:
1354: break;
1355:
1356:
1357: case fra_order:
1358:
1359: if (ordercnt < 0) goto zinv;
1360:
1361: offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
1362:
1363: if (addr >= offset) { /* look in next block */
1364:
1365: if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
1366: data[0] = EOL1;
1367: g_o_val[0] = EOL;
1368:
1369: goto quit;
1370: } /* no next block */
1.24 ! snw 1371:
! 1372: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1373: read (filedes, block, BLOCKLEN);
1.1 snw 1374: scandblk (block, &addr, &found);
1375:
1376: }
1377:
1378: {
1379: long len;
1380: int ch0;
1381: char scratch[256];
1382: char key0[256];
1383:
1384: i = 0;
1385:
1386: while (i <= addr) { /* compute offset complete key */
1387:
1388: len = UNSIGN (block[i++]);
1389: len += (j = UNSIGN (block[i++]));
1390:
1391: while (j < len) key0[j++] = block[i++];
1392:
1393: key0[j] = g_EOL;
1394: i += UNSIGN (block[i]);
1395:
1396: i++; /* skip data */
1397: }
1398:
1399: /* save data value for inspection with $V(111) */
1400: i = addr;
1401: i += UNSIGN (block[i]);
1402: i += 2; /* skip key */
1403: j = UNSIGN (block[i++]);
1404: stcpy0 (g_o_val, &block[i], j); /* get value */
1405: g_o_val[j] = EOL; /* append EOL */
1406:
1407: i = 0;
1408: j = 0;
1409:
1410: while ((scratch[j++] = UNSIGN (key0[i++])) != g_EOL);
1411:
1412: if (compactkey[--keyl] == ALPHA) keyl++;
1413:
1414: /* count subscripts of key */
1415: i = 0;
1416: j1 = 0;
1417:
1418: while (i < keyl) if (compactkey[i++] & 01)
1419:
1.24 ! snw 1420: j1++;
1.1 snw 1421: i = 0;
1422: j = 0;
1423: k = 0;
1424:
1425: while (i < keyl) {
1426:
1427: if (scratch[i] != compactkey[j++]) {
1428: k++;
1429: break;
1430: }
1431:
1432: if (scratch[i++] & 01) k++;
1433:
1434: }
1435:
1436: if (k < j1) {
1437: data[0] = EOL1;
1438: g_o_val[0] = EOL;
1439:
1440: goto quit;
1441: }
1442:
1443: while (--i >= 0) {
1444: if ((scratch[i] & 01)) break;
1445: }
1446:
1447: i++;
1448: j = 0;
1449:
1450: while ((ch = UNSIGN (scratch[i++])) != g_EOL) {
1451:
1452: ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
1.24 ! snw 1453: (ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
! 1454: (ch >> 1) + SP)); /* '.' or '-' */
1.1 snw 1455:
1456:
1457: if (ch0 == DEL) {
1458:
1459: if (((ch = UNSIGN (scratch[i++])) >> 1) == DEL) {
1460: ch0 += DEL;
1461: ch = UNSIGN (scratch[i++]);
1462: }
1463:
1464: ch0 += (ch >> 1);
1465: }
1466:
1467: data[j++] = ch0;
1468:
1469: if (ch & 01) break;
1470:
1471: }
1472:
1473: /* forget that data value if $d=10 */
1474: if (UNSIGN (scratch[i]) != g_EOL) g_o_val[0] = EOL;
1475:
1476: data[j] = EOL1;
1477: ordercounter++;
1478:
1479: if (--ordercnt > 0) { /* repeated forward scanning */
1480:
1481: if (ch != g_EOL) scratch[i] = g_EOL;
1482:
1483: stcpy0 (compactkey, scratch, i + 1);
1484:
1485: compactkey[i - 1] |= 01;
1486: compactkey[i] = OMEGA;
1487: keyl = i + 1;
1488:
1489: goto k_again;
1490:
1491: }
1492:
1493: }
1494:
1495: break;
1496:
1497:
1498: case fra_query:
1499:
1500: if (ordercnt < 1) {
1501: merr_raise (ARGLIST);
1502: goto quit;
1503: }
1504:
1505: if (found == 2) { /* ... advance to next entry */
1506: addr += UNSIGN (block[addr]);
1507: addr += 2; /* skip key */
1508: addr += UNSIGN (block[addr]);
1509: addr++; /* skip data */
1510: }
1511:
1512: offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
1513:
1514: while (--ordercnt > 0) { /* repeated forward query */
1515:
1516: addr += UNSIGN (block[addr]);
1517: addr += 2; /* skip key */
1518: addr += UNSIGN (block[addr]);
1519: addr++; /* skip data */
1520:
1521: if (addr >= offset) { /* look in next block */
1522:
1523: if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
1524: data[0] = EOL1;
1525:
1526: goto quit; /* no next block */
1527: }
1528:
1.24 ! snw 1529: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1530: read (filedes, block, BLOCKLEN);
1.1 snw 1531:
1532: addr = 0;
1533: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 1534: UNSIGN (block[OFFS + 1]);
1.1 snw 1535: }
1536:
1537: }
1538:
1539: if (addr >= offset) { /* look in next block */
1540:
1541: if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
1542:
1543: if (getnflag) {
1544: zref[0] = EOL;
1545: merr_raise (ARGER);
1546: }
1547:
1548: data[0] = EOL1;
1549:
1550: goto quit; /* no next block */
1551: }
1552:
1.24 ! snw 1553: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1554: read (filedes, block, BLOCKLEN);
1.1 snw 1555:
1556: addr = 0;
1557: }
1558:
1559: {
1560: long len;
1561: char key0[256];
1562:
1563: i = 0;
1564:
1565: while (i <= addr) { /* compute offset complete key */
1566:
1567: len = UNSIGN (block[i++]);
1568: len += (j = UNSIGN (block[i++]));
1569:
1570: while (j < len) key0[j++] = block[i++];
1571:
1572: key0[j] = g_EOL;
1573: k = i; /* save i for getnflag processing */
1574: i += UNSIGN (block[i]);
1575: i++; /* skip data */
1576:
1577: }
1578:
1579: if (getnflag) {
1580:
1581: int ch0;
1582:
1583: i = k;
1584: k = UNSIGN (block[i++]);
1585:
1586: stcpy0 (data, &block[i], k); /* get value */
1587:
1588: data[k] = EOL1; /* append EOL */
1589: j = 0;
1590:
1591: while (zref[j] != DELIM && zref[j] != EOL) j++;
1592:
1593: if (zref[j] == EOL) zref[j] = DELIM;
1594:
1595: nakoffs = j;
1596: j++;
1597: i = 0; /* make this ref $ZR */
1598:
1599: while ((ch = UNSIGN (key0[i++])) != g_EOL) {
1600:
1601: ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
1.24 ! snw 1602: (ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
! 1603: (ch >> 1) + SP)); /* '.' or '-' */
1.1 snw 1604:
1605:
1606: if (ch0 == DEL) {
1607:
1608: if (((ch = UNSIGN (key0[i++])) >> 1) == DEL) {
1609: ch0 += DEL;
1610: ch = UNSIGN (key0[i++]);
1611: }
1612:
1613: ch0 += (ch >> 1);
1614:
1615: }
1616:
1617: zref[j++] = ch0;
1.5 snw 1618:
1.1 snw 1619:
1620: if (j >= 252) {
1621: zref[j] = EOL;
1622: merr_raise (M75);
1623:
1624: goto quit;
1625: }
1626:
1627: if (ch & 01) {
1628: nakoffs = j;
1629: zref[j++] = DELIM;
1630: }
1631:
1632: }
1633:
1634: zref[--j] = EOL;
1635:
1636: break;
1637:
1638: }
1639: else { /* save data value for inspection with $V(111) */
1640:
1641: int ch0;
1642:
1643: i = addr;
1644: i += UNSIGN (block[i]);
1645: i += 2; /* skip key */
1646: j = UNSIGN (block[i++]);
1647:
1648: stcpy0 (g_o_val, &block[i], j); /* get value */
1649:
1650: g_o_val[j] = EOL; /* append EOL */
1651:
1652: j = 0;
1653: i = 0;
1654:
1655: while ((data[j] = zref[j]) != DELIM) {
1656:
1657: if (data[j] == EOL1) {
1658: data[j] = '(';
1659: break;
1660: }
1661:
1662: j++;
1663:
1664: }
1665:
1666: data[j++] = '(';
1667: k = 1;
1668:
1669: while ((ch = UNSIGN (key0[i++])) != g_EOL) {
1670: int typ;
1671:
1672: if (k) {
1673: k = 0;
1674:
1675: if ((typ = (ch > SP))) data[j++] = '"';
1676: }
1677:
1678: ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
1.24 ! snw 1679: (ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
! 1680: (ch >> 1) + SP)); /* '.' or '-' */
1.1 snw 1681:
1682: if (ch0 == DEL) {
1683:
1684: if (((ch = UNSIGN (key0[i++])) >> 1) == DEL) {
1685: ch0 += DEL;
1686: ch = UNSIGN (key0[i++]);
1687: }
1688:
1689: ch0 += (ch >> 1);
1690: }
1691:
1692: data[j] = ch0;
1693:
1694: if (j >= 252) {
1695: data[j] = EOL1;
1696: merr_raise (M75);
1697:
1698: goto quit;
1699: }
1700:
1701: if (data[j++] == '"') data[j++] = '"';
1702:
1703: if (ch & 01) {
1704:
1705: if (typ) data[j++] = '"';
1706:
1707: data[j++] = ',';
1708: k = 1;
1709:
1710: }
1711: }
1712:
1713: data[j--] = EOL1;
1714: data[j] = ')';
1715:
1716: }
1717: }
1718:
1719: break;
1720:
1721:
1722: case kill_sym: /* search and destroy */
1723:
1.24 ! snw 1724: killo: /* entry from killone section */
1.1 snw 1725: offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
1726:
1727: i = 0;
1728: key1[0] = g_EOL;
1729:
1730: while (i < addr) { /* compute complete key */
1731:
1732: k = UNSIGN (block[i++]);
1733: k += (j = UNSIGN (block[i++]));
1734:
1735: while (j < k) key1[j++] = block[i++];
1736:
1737: key1[j] = g_EOL;
1738: i += UNSIGN (block[i]);
1739:
1740: i++; /* skip data */
1741:
1742: }
1743:
1744: /* look whether there's something to do at all */
1745: if (found != 2) { /* is it a descendant ? */
1746:
1747: char key0[256];
1748: long trxsav;
1749:
1750: if (addr >= offset) { /* nothing to kill in that block */
1751:
1752: blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]);
1753:
1754: if (blknbr == 0) break; /* there is no next block */
1755:
1756: /* maybe there's something in the next block ... */
1757: trxsav = trx;
1758:
1759: for (;;) {
1760:
1761: other = traceblk[--trx];
1762: addr = traceadr[trx];
1.24 ! snw 1763:
! 1764: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 1765: read (filedes, block, BLOCKLEN);
1.1 snw 1766:
1767: addr += UNSIGN (block[addr]);
1768: addr += (2 + PLEN); /* skip previous entry */
1769: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 1770: UNSIGN (block[OFFS + 1]);
1.1 snw 1771: traceadr[trx] = addr;
1772:
1773: if (addr < offset) break;
1774:
1775: traceadr[trx] = 0;
1776: traceblk[trx] = UNSIGN (block[RLPTR]) * 65536 +
1.24 ! snw 1777: UNSIGN (block[RLPTR + 1]) * 256 +
! 1778: UNSIGN (block[RLPTR + 2]);
1.1 snw 1779:
1780: }
1781:
1782: trx = trxsav;
1783:
1.24 ! snw 1784: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 1785: read (filedes, block, BLOCKLEN);
1.1 snw 1786:
1787: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 1788: UNSIGN (block[OFFS + 1]);
1.1 snw 1789: addr = 0;
1790: k = UNSIGN (block[0]);
1791: stcpy0 (key0, &block[2], k);
1792: key0[k] = g_EOL;
1793:
1794: }
1795: else { /* get following entry */
1796:
1797: stcpy0 (key0, key1, j);
1798: i = addr;
1799: k = UNSIGN (block[i++]);
1800: k += (j = UNSIGN (block[i++]));
1801:
1802: while (j < k) key0[j++] = block[i++];
1803:
1804: key0[j] = g_EOL;
1805: }
1806:
1807: /* is it a descendant? */
1808: i = 0;
1809:
1810: while (compactkey[i] == key0[i]) i++;
1811:
1812: if (compactkey[i] != g_EOL) break; /* nothing to kill */
1813: }
1814:
1815: /* scan this block for all descendants */
1816: {
1817:
1818: long begadr, endadr, len;
1819: char key0[256];
1820:
1821: stcpy0 (key0, compactkey, (long) keyl);
1822:
1823: begadr = endadr = i = addr;
1824:
1825: if (action == killone) {
1826:
1827: i += UNSIGN (block[i]);
1828: i += 2; /* skip key */
1829: i += UNSIGN (block[i]);
1830: i++; /* skip data */
1831:
1832: endadr = i;
1833: }
1834: else {
1835:
1836: while (i < offset) {
1837:
1838: len = UNSIGN (block[i++]);
1839: k = j = UNSIGN (block[i++]);
1840:
1841: if (k >= keyl) {
1842: i += len;
1843: }
1844: else {
1845:
1846: len += k;
1847:
1848: while (j < len) key0[j++] = block[i++];
1849:
1850: key0[j] = g_EOL;
1851:
1852: /* k=0; ueberfluessig */
1853: while (compactkey[k] == key0[k]) {
1854:
1855: if (compactkey[k] == g_EOL) break;
1856:
1857: k++;
1858: }
1859:
1860: if (compactkey[k] != g_EOL) break; /* no descendant */
1861:
1862: }
1863:
1864: i += UNSIGN (block[i]);
1865: i++; /* skip data */
1866: endadr = i;
1867:
1868: }
1869:
1870: }
1871:
1872: kill_again = (endadr == offset && action != killone); /* may be there's more to kill */
1873:
1874: if ((begadr == 0) && (endadr == offset)) { /* block becomes empty */
1875:
1876: long left,
1.24 ! snw 1877: right;
1.1 snw 1878: char block0[BLOCKLEN];
1879:
1.24 ! snw 1880: p_empty: /* entry if pointer block goes empty */
1.1 snw 1881:
1882: left = UNSIGN (block[LLPTR]) * 65536 +
1.24 ! snw 1883: UNSIGN (block[LLPTR + 1]) * 256 +
! 1884: UNSIGN (block[LLPTR + 2]);
1.1 snw 1885: right = UNSIGN (block[RLPTR]) * 65536 +
1.24 ! snw 1886: UNSIGN (block[RLPTR + 1]) * 256 +
! 1887: UNSIGN (block[RLPTR + 2]);
1.1 snw 1888:
1889: if (left) {
1890:
1.24 ! snw 1891: lseek (filedes, (long) left * (long) (BLOCKLEN), 0);
! 1892: read (filedes, block0, BLOCKLEN);
1.1 snw 1893:
1894: block0[RLPTR] = block[RLPTR];
1895: block0[RLPTR + 1] = block[RLPTR + 1];
1896: block0[RLPTR + 2] = block[RLPTR + 2];
1.24 ! snw 1897:
! 1898: lseek (filedes, (long) left * (long) (BLOCKLEN), 0);
! 1899: write (filedes, block0, BLOCKLEN);
1.1 snw 1900:
1901: }
1902:
1903: if (right) {
1.24 ! snw 1904:
! 1905: lseek (filedes, (long) right * (long) (BLOCKLEN), 0);
! 1906: read (filedes, block0, BLOCKLEN);
1.1 snw 1907:
1908: block0[LLPTR] = block[LLPTR];
1909: block0[LLPTR + 1] = block[LLPTR + 1];
1910: block0[LLPTR + 2] = block[LLPTR + 2];
1.24 ! snw 1911:
! 1912: lseek (filedes, (long) right * (long) (BLOCKLEN), 0);
! 1913: write (filedes, block0, BLOCKLEN);
1.1 snw 1914:
1915: }
1916:
1.24 ! snw 1917: b_free (filedes, blknbr); /* modify free list */
1.1 snw 1918:
1919: /* delete pointer */
1920: /**************************/
1921: {
1922: long trxsav;
1923: long freecnt;
1924:
1925: trxsav = trx;
1926:
1927: blknbr = traceblk[--trx];
1928: addr = traceadr[trx];
1929:
1.24 ! snw 1930: lseek (filedes, (long) (blknbr) * (long) (BLOCKLEN), 0);
! 1931: read (filedes, block, BLOCKLEN);
1.1 snw 1932: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 1933: UNSIGN (block[OFFS + 1]);
1.1 snw 1934: freecnt = UNSIGN (block[addr]) + 2 + PLEN;
1935:
1936: /* delete key */
1937: offset -= freecnt;
1938:
1939: if (offset == 0) { /* pointer block went empty */
1940:
1941: if (blknbr == ROOT) { /* global went empty */
1942:
1.24 ! snw 1943: lseek (filedes, 0L, 0);
1.1 snw 1944:
1945: /* note : UNIX does not tell other */
1946: block[BTYP] = EMPTY; /* jobs that a file has been unlinked */
1947:
1948: /* as long as they keep it open. */
1949: /* so we mark this global as EMPTY */
1.24 ! snw 1950: write (filedes, block, BLOCKLEN);
! 1951: close (filedes);
1.1 snw 1952: unlink (filnam);
1.24 ! snw 1953:
! 1954: if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
1.1 snw 1955:
1956: olddes[inuse] = 0;
1957: oldfil[inuse][0] = NUL;
1958: usage[inuse] = 0;
1959:
1960: return;
1961:
1962: }
1963:
1964: goto p_empty; /* clear pointer block */
1965:
1966: }
1967:
1968: block[OFFS] = offset / 256;
1969: block[OFFS + 1] = offset % 256;
1970:
1971: stcpy0 (&block[addr], &block[addr + freecnt], (long) (offset - addr));
1972:
1973: for (i = offset; i < offset + freecnt; block[i++] = 0);
1974:
1.24 ! snw 1975: lseek (filedes, (long) (blknbr) * (long) (BLOCKLEN), 0);
! 1976: write (filedes, block, BLOCKLEN);
1.1 snw 1977:
1978: if (addr == 0) { /* update of pointer */
1979: traceadr[trx] = 0;
1980:
1.24 ! snw 1981: update (filedes, &block[2], (long) UNSIGN (block[0]));
1.1 snw 1982: }
1983:
1984: trx = trxsav;
1985:
1986: }
1987:
1988: if (kill_again) goto k_again;
1989:
1990: break;
1991: }
1992:
1993: i = begadr;
1994: j = endadr;
1995:
1996: while (j < offset) block[i++] = block[j++];
1997: while (i < offset) block[i++] = 0;
1998:
1999: /** clear rest */
2000: offset += (begadr - endadr);
2001: if (begadr < offset && block[begadr + 1]) { /* new key_offset for next entry */
2002: i = block[begadr];
2003: j = block[begadr + 1];
2004: k = 0;
2005: if (begadr)
1.24 ! snw 2006: while (key0[k] == key1[k])
! 2007: k++; /* new key_offset */
1.1 snw 2008: if (k < j) {
1.24 ! snw 2009: ch = j - k; /* space requirement */
! 2010: block[begadr] = i + ch; /* new key_length */
! 2011: block[begadr + 1] = k; /* new key_offset */
! 2012: i = offset;
! 2013: j = i + ch;
! 2014: offset = j;
! 2015: begadr++;
! 2016: while (i > begadr)
! 2017: block[j--] = block[i--];
! 2018: stcpy0 (&block[begadr + 1], &key0[k], ch);
1.1 snw 2019: }
2020: }
2021: block[OFFS] = offset / 256;
2022: block[OFFS + 1] = offset % 256;
1.24 ! snw 2023: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2024: write (filedes, block, BLOCKLEN);
1.1 snw 2025: if (addr < 3) { /* update of pointer */
1.24 ! snw 2026: traceadr[trx] = 0;
! 2027: update (filedes, &block[2], (long) UNSIGN (block[0]));
1.1 snw 2028: }
2029: }
2030:
2031: if (kill_again) goto k_again;
2032:
2033: break;
2034:
1.24 ! snw 2035: zinv:
1.1 snw 2036:
2037: {
2038: long len;
2039: int ch0;
2040: char scratch[256];
2041: char key0[256];
2042:
2043: if (addr <= 0) { /* look in previous block */
2044:
2045: if ((blknbr = UNSIGN (block[LLPTR]) * 65536 + UNSIGN (block[LLPTR + 1]) * 256 + UNSIGN (block[LLPTR + 2])) == 0) {
2046: data[0] = EOL1;
2047: goto quit;
2048: } /* no previous block */
1.24 ! snw 2049:
! 2050: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2051: read (filedes, block, BLOCKLEN);
1.1 snw 2052:
2053: addr = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 2054: UNSIGN (block[OFFS + 1]);
1.1 snw 2055:
2056: }
2057:
2058: i = 0;
2059:
2060: while (i < addr) { /* compute offset complete key */
2061:
2062: len = UNSIGN (block[i++]);
2063: len += (j = UNSIGN (block[i++]));
2064:
2065: while (j < len) key0[j++] = block[i++];
2066:
2067: key0[j] = g_EOL;
2068: j1 = i;
2069: i += UNSIGN (block[i]);
2070: i++; /* skip data */
2071:
2072: }
2073:
2074: /* save data value for inspection with $V(111) */
2075: j = UNSIGN (block[j1++]);
2076:
2077: stcpy0 (g_o_val, &block[j1], j); /* get value */
2078: g_o_val[j] = EOL; /* append EOL */
2079:
2080: i = 0;
2081: j = 0;
2082:
2083: while ((scratch[j++] = UNSIGN (key0[i++])) != g_EOL);
2084:
2085: /* count subscripts of key */
2086: i = 0;
2087: j1 = 0;
2088:
2089: while (i < keyl) {
2090:
2091: if (compactkey[i++] & 01) {
2092: j1++;
2093: }
2094:
2095: }
2096:
2097: i = 0;
2098: j = 0;
2099: k = 0;
2100:
2101: while (i < keyl) {
2102:
2103: if (scratch[i] != compactkey[j++]) {
2104: k++;
2105: break;
2106: }
2107:
2108: if (scratch[i++] & 01) k++;
2109:
2110: }
2111:
2112: if (k < j1) {
2113: data[0] = EOL1;
2114: g_o_val[0] = EOL;
2115:
2116: goto quit;
2117: }
2118:
2119: while (--i >= 0) {
2120: if ((scratch[i] & 01)) break;
2121: }
2122:
2123: i++;
2124: j = 0;
2125:
2126: while ((ch = UNSIGN (scratch[i++])) != g_EOL) {
2127:
2128: ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
1.24 ! snw 2129: (ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
! 2130: (ch >> 1) + SP)); /* '.' or '-' */
1.1 snw 2131:
2132: if (ch0 == DEL) {
2133:
2134: if (((ch = UNSIGN (scratch[i++])) >> 1) == DEL) {
2135: ch0 += DEL;
2136: ch = UNSIGN (scratch[i++]);
2137: }
2138:
2139: ch0 += (ch >> 1);
2140:
2141: }
2142:
2143: data[j++] = ch0;
2144:
2145: if (ch & 01) break;
2146:
2147: }
2148:
2149: data[j] = EOL1;
2150:
2151: if (j == 0) break;
2152:
2153: ordercounter++;
2154:
2155: if (ordercnt++ < (-1)) { /* repeated backward scanning */
2156:
2157: if (ch != g_EOL) scratch[i] = g_EOL;
2158:
2159: stcpy0 (compactkey, scratch, i + 1);
2160:
2161: compactkey[i - 1] |= 01;
2162: keyl = i;
2163:
2164: goto k_again;
2165:
2166: }
2167:
2168: }
2169:
2170: break;
2171:
2172:
2173: case zdata: /* nonstandard data function */
2174:
1.24 ! snw 2175: {
! 2176: long counties[128];
! 2177: char key0[256];
! 2178: int icnt, icnt0, len;
1.1 snw 2179:
1.24 ! snw 2180: i = 0;
1.1 snw 2181:
1.24 ! snw 2182: while (i < 128) counties[i++] = 0L; /* init count; */
1.1 snw 2183:
1.24 ! snw 2184: if (found == 2) { /* ... advance to next entry */
! 2185: addr += UNSIGN (block[addr]);
! 2186: addr += 2; /* skip key */
! 2187: addr += UNSIGN (block[addr]);
! 2188: addr++; /* skip data */
1.1 snw 2189:
1.24 ! snw 2190: counties[0] = 1L;
! 2191: }
1.1 snw 2192:
1.24 ! snw 2193: offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
! 2194: icnt = 0;
! 2195: i = 0;
1.1 snw 2196:
1.24 ! snw 2197: while ((ch = compactkey[i++]) != g_EOL) {
! 2198:
! 2199: if (ch & 01) {
! 2200: icnt++;
! 2201: }
1.1 snw 2202:
1.19 snw 2203: }
1.1 snw 2204:
1.24 ! snw 2205: len = i - 1;
! 2206: i = 0;
1.1 snw 2207:
1.24 ! snw 2208: while (i < addr) { /* compute offset complete key */
1.1 snw 2209:
1.24 ! snw 2210: icnt0 = UNSIGN (block[i++]);
! 2211: icnt0 += (j = UNSIGN (block[i++]));
1.1 snw 2212:
1.24 ! snw 2213: while (j < icnt0) key0[j++] = block[i++];
1.1 snw 2214:
1.24 ! snw 2215: key0[j] = g_EOL;
! 2216: i += UNSIGN (block[i]);
1.1 snw 2217:
1.24 ! snw 2218: i++; /* skip data */
1.1 snw 2219:
1.24 ! snw 2220: }
1.1 snw 2221:
1.24 ! snw 2222: for (;;) { /* is it still a descendant ??? */
1.1 snw 2223:
1.24 ! snw 2224: if (addr >= offset) { /* look in next block */
1.1 snw 2225:
1.24 ! snw 2226: if ((blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2])) == 0) {
! 2227: break; /* no next block */
! 2228: }
1.1 snw 2229:
1.24 ! snw 2230: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2231: read (filedes, block, BLOCKLEN);
1.1 snw 2232:
1.24 ! snw 2233: addr = 0;
! 2234: offset = UNSIGN (block[OFFS]) * 256 +
1.1 snw 2235: UNSIGN (block[OFFS + 1]);
2236:
1.24 ! snw 2237: }
1.1 snw 2238:
1.24 ! snw 2239: i = UNSIGN (block[addr++]);
! 2240: i += (j = UNSIGN (block[addr++]));
1.1 snw 2241:
1.24 ! snw 2242: while (j < i) key0[j++] = block[addr++];
1.1 snw 2243:
1.24 ! snw 2244: addr += UNSIGN (block[addr]);
! 2245: addr++; /* skip data */
! 2246: icnt0 = 0;
! 2247: i = 0;
1.1 snw 2248:
1.24 ! snw 2249: while (i < j) if (key0[i++] & 01)
1.1 snw 2250:
1.24 ! snw 2251: icnt0++;
1.1 snw 2252:
1.24 ! snw 2253: if (icnt0 <= icnt) break;
1.1 snw 2254:
1.24 ! snw 2255: i = 0;
1.1 snw 2256:
1.24 ! snw 2257: while (i < len) {
1.1 snw 2258:
1.24 ! snw 2259: if (key0[i] != compactkey[i]) break;
1.1 snw 2260:
1.24 ! snw 2261: i++;
1.1 snw 2262:
1.24 ! snw 2263: }
1.1 snw 2264:
1.24 ! snw 2265: if (i < len) break;
1.1 snw 2266:
1.24 ! snw 2267: counties[icnt0 - icnt]++;
1.1 snw 2268:
1.24 ! snw 2269: }
1.1 snw 2270:
1.24 ! snw 2271: i = 128;
1.1 snw 2272:
1.24 ! snw 2273: while (counties[--i] == 0L);
1.1 snw 2274:
1.24 ! snw 2275: lintstr (data, counties[0]);
1.1 snw 2276:
1.24 ! snw 2277: j = 1;
! 2278: tmp1[0] = ',';
1.1 snw 2279:
1.24 ! snw 2280: while (j <= i) {
! 2281: lintstr (&tmp1[1], counties[j++]);
! 2282: stcat (data, tmp1);
! 2283: }
! 2284:
1.19 snw 2285: }
1.1 snw 2286:
1.24 ! snw 2287: break;
1.1 snw 2288:
2289: case getinc:
2290:
1.24 ! snw 2291: {
! 2292: int setopsav;
1.1 snw 2293:
1.24 ! snw 2294: setopsav = setop;
! 2295: setop = '+';
! 2296: data[0] = '1';
! 2297: data[1] = EOL;
1.1 snw 2298:
1.24 ! snw 2299: global (set_sym, key, data);
1.1 snw 2300:
1.24 ! snw 2301: setop = setopsav;
1.1 snw 2302:
1.24 ! snw 2303: return;
! 2304: }
1.1 snw 2305:
2306: case killone:
1.24 ! snw 2307:
! 2308: {
! 2309: if (found == 2) goto killo; /* entry found use normal kill routine */
1.1 snw 2310:
1.24 ! snw 2311: goto quit;
! 2312: }
! 2313:
! 2314: case merge_sym:
! 2315:
! 2316: printf("MERGE NOT IMPLEMENTED FOR GLOBALS\n");
! 2317:
! 2318: #ifdef DEBUG_GBL
! 2319:
! 2320: int loop;
! 2321:
! 2322: printf ("DEBUG MERGE: ");
! 2323: printf ("[key] is [");
! 2324:
! 2325: for (loop = 0; key[loop] != EOL; loop++) printf ("%c", (key[loop] == DELIM) ? '!' : key[loop]);
! 2326:
! 2327: printf ("]\r\n");
! 2328: printf ("[data] is [");
! 2329:
! 2330: for(loop = 0; data[loop] != EOL; loop++) printf ("%c", (data[loop] == DELIM) ? '!' : data[loop]);
! 2331:
! 2332: printf("]\r\n");
! 2333:
! 2334: #endif
! 2335: return;
1.1 snw 2336:
2337: default:
2338:
2339: merr_raise (INVREF); /* accidental call with wrong action code (v22-stuff) */
2340: } /* end of switch */
2341:
2342: quit:
2343:
2344: /* clean things up */
2345:
1.24 ! snw 2346: lseek (filedes, ROOT, 0);
! 2347:
! 2348: if (lonelyflag == FALSE) locking (filedes, 0, 0L); /* unlock */
! 2349:
1.1 snw 2350: return;
2351:
2352:
2353: splitd: /* split data block in two sections */
2354:
2355: /* part of the data is taken to an other location. */
2356: /* old information in 'block' stored at 'blknbr' */
2357: /* 'addr' there I would like to insert, if possible (which is not) */
2358: /* 'offset' filled up to this limit */
2359:
1.24 ! snw 2360: getnewblk (filedes, &newblk); /* get a new block */
1.1 snw 2361:
2362: /* if we have to insert at the begin or end of a block */
2363: /* we don't split - we just start a new block */
2364: /* if an insert in the midst of a block, we split */
2365:
2366: if (addr >= offset) {
2367: long right,
1.24 ! snw 2368: right1,
! 2369: right2;
1.1 snw 2370:
2371: right = UNSIGN (block[RLPTR]);
2372: right1 = UNSIGN (block[RLPTR + 1]);
2373: right2 = UNSIGN (block[RLPTR + 2]);
2374: block[RLPTR] = newblk / 65536;
2375: block[RLPTR + 1] = newblk % 65536 / 256;
2376: block[RLPTR + 2] = newblk % 256;
2377:
1.24 ! snw 2378: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2379: write (filedes, block, BLOCKLEN);
1.1 snw 2380:
2381: block[RLPTR] = right;
2382: block[RLPTR + 1] = right1;
2383: block[RLPTR + 2] = right2;
2384: block[LLPTR] = blknbr / 65536;
2385: block[LLPTR + 1] = blknbr % 65536 / 256;
2386: block[LLPTR + 2] = blknbr % 256;
2387: offset = 0;
2388: addr = 0;
2389: blknbr = newblk;
2390:
1.24 ! snw 2391: insert (filedes, compactkey, keyl, newblk);
1.1 snw 2392:
2393: /* up-date LL-PTR of RL-block */
2394: if ((other = right * 65536 + right1 * 256 + right2)) {
2395:
2396: char block0[BLOCKLEN];
2397:
1.24 ! snw 2398: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2399: read (filedes, block0, BLOCKLEN);
1.1 snw 2400:
2401: block0[LLPTR] = blknbr / 65536;
2402: block0[LLPTR + 1] = blknbr % 65536 / 256;
2403: block0[LLPTR + 2] = blknbr % 256;
2404:
1.24 ! snw 2405: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2406: write (filedes, block0, BLOCKLEN);
! 2407:
1.1 snw 2408: }
2409:
2410: goto spltex;
2411: }
2412:
2413: if (addr == 0) {
2414: long left, left1, left2;
2415:
2416: left = UNSIGN (block[LLPTR]);
2417: left1 = UNSIGN (block[LLPTR + 1]);
2418: left2 = UNSIGN (block[LLPTR + 2]);
2419:
2420: block[LLPTR] = newblk / 65536;
2421: block[LLPTR + 1] = newblk % 65536 / 256;
2422: block[LLPTR + 2] = newblk % 256;
2423:
1.24 ! snw 2424: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2425: write (filedes, block, BLOCKLEN);
! 2426:
1.1 snw 2427: block[LLPTR] = left;
2428: block[LLPTR + 1] = left1;
2429: block[LLPTR + 2] = left2;
2430: block[RLPTR] = blknbr / 65536;
2431: block[RLPTR + 1] = blknbr % 65536 / 256;
2432: block[RLPTR + 2] = blknbr % 256;
2433: offset = 0;
2434: blknbr = newblk;
2435: traceadr[trx] = (-1); /* inhibit second update of pointers */
2436:
1.24 ! snw 2437: insert (filedes, compactkey, keyl, newblk);
1.1 snw 2438:
2439: if (addr < 3) { /* update of pointer */
2440: traceadr[trx] = 0;
2441:
1.24 ! snw 2442: update (filedes, compactkey, keyl);
1.1 snw 2443: }
2444:
2445: /* other is ***always*** zero !!!
1.24 ! snw 2446: * if (other=left*65536+left1*256+left2) up-date RL-PTR of LL-block
! 2447: * { char block0[BLOCKLEN];
! 2448: * lseek(filedes,(long)other*(long)(BLOCKLEN),0);
! 2449: * read(filedes,block0,BLOCKLEN);
! 2450: * block0[RLPTR ]=blknbr/65536;
! 2451: * block0[RLPTR+1]=blknbr%65536/256;
! 2452: * block0[RLPTR+2]=blknbr%256;
! 2453: * lseek(filedes,(long)other*(long)(BLOCKLEN),0);
! 2454: * write(filedes,block0,BLOCKLEN);
! 2455: * }
! 2456: */
1.1 snw 2457:
2458: goto spltex;
2459:
2460: }
2461:
2462: {
2463: char block0[BLOCKLEN];
2464: char key0[256];
2465: int newlimit;
2466:
2467: block0[BTYP] = DATA;
2468:
2469: /* now search for a dividing line */
2470: limit = (offset + needed) / 2;
2471: i = (offset - needed) / 2;
2472:
2473: if (addr < i) limit = i;
2474:
2475: i = 0;
2476: newlimit = i;
2477:
2478: while (i < limit) {
2479:
2480: newlimit = i;
2481: j = UNSIGN (block[i++]); /* length of key - offset */
2482: k = UNSIGN (block[i++]); /* offset into previous entry */
2483: j += k;
2484:
2485: while (k < j) key0[k++] = block[i++]; /* get key */
2486:
2487: key0[k] = g_EOL;
2488: i += UNSIGN (block[i]);
2489: i++; /* skip data */
2490:
2491: }
2492:
2493: limit = newlimit;
2494: i = newlimit;
2495:
2496: j = i;
2497: i = 0; /* copy part of old to new blk */
2498:
2499: if ((k = UNSIGN (block[j + 1])) != 0) { /* expand key */
2500:
2501: block0[i++] = UNSIGN (block[j++]) + k;
2502: block0[i++] = 0;
2503:
2504: if (addr > limit) addr += k;
2505:
2506: j = 0;
2507:
2508: while (j < k) block0[i++] = key0[j++];
2509:
2510: j = limit + 2;
2511:
2512: }
2513:
2514: while (j < offset) {
2515:
2516: block0[i++] = block[j];
2517: block[j] = 0;
2518:
2519: j++;
2520:
2521: }
2522:
2523: while (i <= DATALIM) block0[i++] = 0; /* clear rest of block */
2524:
2525: offset -= limit;
2526:
2527: if (k > 0) offset += k; /* new offsets */
2528:
2529: block[OFFS] = limit / 256;
2530: block[OFFS + 1] = limit % 256;
2531: block0[OFFS] = offset / 256;
2532: block0[OFFS + 1] = offset % 256;
2533:
2534: if (addr <= limit) { /* save new block away */
2535:
2536: /* update rightlink and leftlink pointers */
2537: other = UNSIGN (block[RLPTR]) * 65536 +
1.24 ! snw 2538: UNSIGN (block[RLPTR + 1]) * 256 +
! 2539: UNSIGN (block[RLPTR + 2]);
1.1 snw 2540: block0[RLPTR] = block[RLPTR];
2541: block0[RLPTR + 1] = block[RLPTR + 1];
2542: block0[RLPTR + 2] = block[RLPTR + 2];
2543: block[RLPTR] = newblk / 65536;
2544: block[RLPTR + 1] = newblk % 65536 / 256;
2545: block[RLPTR + 2] = newblk % 256;
2546: block0[LLPTR] = blknbr / 65536;
2547: block0[LLPTR + 1] = blknbr % 65536 / 256;
2548: block0[LLPTR + 2] = blknbr % 256;
2549:
1.24 ! snw 2550: lseek (filedes, (long) (newblk) * (long) (BLOCKLEN), 0);
! 2551: write (filedes, block0, BLOCKLEN);
1.1 snw 2552:
2553: offset = limit;
2554: /* insert new block in pointer structure */
2555:
1.24 ! snw 2556: insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
1.1 snw 2557:
2558: /* up-date LL-PTR of RL-block */
2559: if (other != 0) {
2560:
1.24 ! snw 2561: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2562: read (filedes, block0, BLOCKLEN);
1.1 snw 2563:
2564: block0[LLPTR] = newblk / 65536;
2565: block0[LLPTR + 1] = newblk % 65536 / 256;
2566: block0[LLPTR + 2] = newblk % 256;
1.24 ! snw 2567:
! 2568: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2569: write (filedes, block0, BLOCKLEN);
1.1 snw 2570:
2571: }
2572:
2573: }
2574: else {
2575: /* save old block away and make new block the current block */
2576: /* update rightlink and leftlink pointers */
2577: other = UNSIGN (block[RLPTR]) * 65536 +
1.24 ! snw 2578: UNSIGN (block[RLPTR + 1]) * 256 +
! 2579: UNSIGN (block[RLPTR + 2]);
1.1 snw 2580: block0[RLPTR] = block[RLPTR];
2581: block0[RLPTR + 1] = block[RLPTR + 1];
2582: block0[RLPTR + 2] = block[RLPTR + 2];
2583: block[RLPTR] = newblk / 65536;
2584: block[RLPTR + 1] = newblk % 65536 / 256;
2585: block[RLPTR + 2] = newblk % 256;
2586: block0[LLPTR] = blknbr / 65536;
2587: block0[LLPTR + 1] = blknbr % 65536 / 256;
2588: block0[LLPTR + 2] = blknbr % 256;
2589:
1.24 ! snw 2590: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2591: write (filedes, block, BLOCKLEN);
1.1 snw 2592: stcpy0 (block, block0, (long) BLOCKLEN);
2593:
2594: traceadr[trx] = (addr -= limit);
2595: traceblk[trx] = (blknbr = newblk);
2596:
2597: /* insert new block in pointer structure */
1.24 ! snw 2598: insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
1.1 snw 2599:
2600: /* up-date LL-PTR of RL-block */
2601: if (other != 0) {
2602:
1.24 ! snw 2603: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2604: read (filedes, block0, BLOCKLEN);
1.1 snw 2605:
2606: block0[LLPTR] = newblk / 65536;
2607: block0[LLPTR + 1] = newblk % 65536 / 256;
2608: block0[LLPTR + 2] = newblk % 256;
1.24 ! snw 2609:
! 2610: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2611: write (filedes, block0, BLOCKLEN);
1.1 snw 2612:
2613: }
2614:
2615: }
2616: }
2617:
2618: spltex:
2619:
2620: if (ret_to == 'n') goto s10;
2621:
2622: goto s20;
2623: } /* end global() */
2624:
2625: /*
2626: * split pointer block in two sections
2627: * filedes: global file descriptor
2628: * block: old block (which is too small)
2629: * addr: addr of entry where to insert
2630: * offs: offset of block
2631: * blknbr: number of old block
2632: *
2633: * part of the data is taken to an other location.
2634: * old information in 'block' stored at 'blknbr'
2635: * 'addr' there I would like to insert, if possible (which is not)
2636: * 'offset' filled up to this limit
2637: */
1.24 ! snw 2638: static void splitp (short filedes, char *block, long *addr, long *offs, unsigned long *blknbr)
1.1 snw 2639: {
2640:
2641: char block0[BLOCKLEN];
2642: long limit;
2643: unsigned long newblk;
2644: unsigned long other;
2645: register int i, j;
1.24 ! snw 2646:
! 2647: getnewblk (filedes, &newblk); /* get a new block */
1.1 snw 2648:
2649: if (*blknbr == ROOT) { /* ROOT overflow is special */
2650:
2651: stcpy0 (block0, block, (long) BLOCKLEN);
2652:
2653: /* clear pointers */
2654: block[LLPTR] = 0;
2655: block[LLPTR + 1] = 0;
2656: block[LLPTR + 2] = 0;
2657: block[RLPTR] = 0;
2658: block[RLPTR + 1] = 0;
2659: block[RLPTR + 2] = 0;
2660:
2661: /* old root block is a 'normal' block now */
2662: /* new root points to a single block */
2663: i = UNSIGN (block0[0]) + 2;
2664: block0[i++] = newblk / 65536;
2665: block0[i++] = newblk % 65536 / 256;
2666: block0[i++] = newblk % 256;
2667: block0[OFFS] = i / 256;
2668: block0[OFFS + 1] = i % 256;
2669:
2670: while (i < DATALIM) block0[i++] = 0; /* clear rest */
2671:
2672: /* update number of blocks ! */
2673: i = UNSIGN (block0[NRBLK]) * 65536 +
1.24 ! snw 2674: UNSIGN (block0[NRBLK + 1]) * 256 +
! 2675: UNSIGN (block0[NRBLK + 2]) + 1;
1.1 snw 2676:
2677: block0[NRBLK] = i / 65536;
2678: block0[NRBLK + 1] = i % 65536 / 256;
2679: block0[NRBLK + 2] = i % 256;
2680: block0[BTYP] = POINTER;
2681:
1.24 ! snw 2682: lseek (filedes, ROOT, 0);
! 2683: write (filedes, block0, BLOCKLEN);
1.1 snw 2684:
2685: /* shift trace_stack */
2686: j = trx++;
2687: i = trx;
2688:
2689: /** if (j>=TRLIM) 'global too big' */
2690: while (j >= 0) {
2691: traceblk[i] = traceblk[j];
2692: traceadr[i--] = traceadr[j--];
2693: }
2694:
2695: traceblk[0] = 0; /*ROOT */
2696: traceadr[0] = 0;
2697: traceblk[1] = newblk;
2698: *blknbr = newblk;
2699:
1.24 ! snw 2700: getnewblk (filedes, &newblk); /* get a new block */
1.1 snw 2701:
2702: }
2703:
2704: block0[BTYP] = block[BTYP];
2705:
2706: /* now search for a dividing line */
2707: i = 0;
2708: limit = (*offs) / 2;
2709:
2710: while (i < limit) {
2711: i += UNSIGN (block[i]);
2712: i += 2; /* skip key */
2713: i += PLEN; /* skip data */
2714: }
2715:
2716: /* new offsets */
2717: limit = i;
2718:
2719: i = (*offs) - limit;
2720:
2721: block[OFFS] = limit / 256;
2722: block[OFFS + 1] = limit % 256;
2723: block0[OFFS] = i / 256;
2724: block0[OFFS + 1] = i % 256;
2725:
2726: for (i = 0; i <= DATALIM; block0[i++] = 0);
2727:
2728: i = 0;
2729: j = limit; /* copy part of old to new blk */
2730:
2731: while (j < (*offs)) {
2732: block0[i++] = block[j];
2733: block[j] = 0;
2734:
2735: j++;
2736: }
2737:
2738: if ((*addr) <= limit) { /* save new block away */
2739:
2740: /* update rightlink and leftlink pointers */
2741: other = UNSIGN (block[RLPTR]) * 65536 +
1.24 ! snw 2742: UNSIGN (block[RLPTR + 1]) * 256 +
! 2743: UNSIGN (block[RLPTR + 2]);
1.1 snw 2744: block0[RLPTR] = block[RLPTR];
2745: block0[RLPTR + 1] = block[RLPTR + 1];
2746: block0[RLPTR + 2] = block[RLPTR + 2];
2747: block[RLPTR] = newblk / 65536;
2748: block[RLPTR + 1] = newblk % 65536 / 256;
2749: block[RLPTR + 2] = newblk % 256;
2750: block0[LLPTR] = (*blknbr) / 65536;
2751: block0[LLPTR + 1] = (*blknbr) % 65536 / 256;
2752: block0[LLPTR + 2] = (*blknbr) % 256;
2753:
1.24 ! snw 2754: lseek (filedes, (long) (newblk) * (long) (BLOCKLEN), 0);
! 2755: write (filedes, block0, BLOCKLEN);
1.1 snw 2756:
2757: (*offs) = limit;
2758:
1.24 ! snw 2759: insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
1.1 snw 2760:
2761: /* up-date LL-PTR of RL-block */
2762: if (other != 0) {
2763:
1.24 ! snw 2764: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2765: read (filedes, block0, BLOCKLEN);
1.1 snw 2766:
2767: block0[LLPTR] = newblk / 65536;
2768: block0[LLPTR + 1] = newblk % 65536 / 256;
2769: block0[LLPTR + 2] = newblk % 256;
1.24 ! snw 2770:
! 2771: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2772: write (filedes, block0, BLOCKLEN);
1.1 snw 2773:
2774: }
2775:
2776: }
2777: else { /* save old block away and make new block the current block */
2778:
2779: /* update rightlink and leftlink pointers */
2780: other = UNSIGN (block[RLPTR]) * 65536 +
1.24 ! snw 2781: UNSIGN (block[RLPTR + 1]) * 256 +
! 2782: UNSIGN (block[RLPTR + 2]);
1.1 snw 2783:
2784: block0[RLPTR] = block[RLPTR];
2785: block0[RLPTR + 1] = block[RLPTR + 1];
2786: block0[RLPTR + 2] = block[RLPTR + 2];
2787: block[RLPTR] = newblk / 65536;
2788: block[RLPTR + 1] = newblk % 65536 / 256;
2789: block[RLPTR + 2] = newblk % 256;
2790: block0[LLPTR] = (*blknbr) / 65536;
2791: block0[LLPTR + 1] = (*blknbr) % 65536 / 256;
2792: block0[LLPTR + 2] = (*blknbr) % 256;
2793:
2794: (*addr) -= limit;
2795: (*offs) -= limit;
2796:
1.24 ! snw 2797: lseek (filedes, (long) (*blknbr) * (long) (BLOCKLEN), 0);
! 2798: write (filedes, block, BLOCKLEN);
1.1 snw 2799: stcpy0 (block, block0, (long) BLOCKLEN);
2800:
2801: (*blknbr) = newblk;
2802:
1.24 ! snw 2803: insert (filedes, &block0[2], (long) UNSIGN (block0[0]), newblk);
1.1 snw 2804:
2805: /* up-date LL-PTR of RL-block */
2806: if (other != 0) {
2807:
1.24 ! snw 2808: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2809: read (filedes, block0, BLOCKLEN);
1.1 snw 2810:
2811: block0[LLPTR] = newblk / 65536;
2812: block0[LLPTR + 1] = newblk % 65536 / 256;
2813: block0[LLPTR + 2] = newblk % 256;
1.24 ! snw 2814:
! 2815: lseek (filedes, (long) other * (long) (BLOCKLEN), 0);
! 2816: write (filedes, block0, BLOCKLEN);
1.1 snw 2817:
2818: }
2819:
2820: }
2821:
2822: return;
2823:
2824: } /* end of splitp() */
2825:
2826: /* update pointer
2827: * filedes: file descriptor
2828: * ins_key: key to be inserted
2829: * keyl: length of that key
2830: */
1.24 ! snw 2831: static void update (short filedes, char *ins_key, long keyl)
1.1 snw 2832: {
2833: long offset;
2834: long addr;
2835: unsigned long blknbr;
2836: char block[BLOCKLEN];
2837: long i, j, k;
1.24 ! snw 2838:
1.1 snw 2839: while (traceadr[trx] == 0) { /* update of pointer blocks necessary */
2840:
2841: if (--trx < 0) break;
2842:
2843: blknbr = traceblk[trx];
2844: addr = traceadr[trx];
1.24 ! snw 2845:
! 2846: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2847: read (filedes, block, BLOCKLEN);
1.1 snw 2848:
2849: {
2850: long oldkeyl;
2851:
2852: oldkeyl = UNSIGN (block[addr]);
2853:
2854: i = addr + keyl + 1;
2855: j = oldkeyl - keyl;
2856:
2857: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 2858: UNSIGN (block[OFFS + 1]);
1.1 snw 2859:
2860: if (j > 0) { /* surplus space */
2861:
2862: k = offset;
2863: offset -= j;
2864: j += i;
2865:
2866: while (i < offset) block[i++] = block[j++];
2867:
2868: while (i < k) block[i++] = 0; /* clear area */
2869:
2870: }
2871: else if (j < 0) { /* we need more space */
2872:
2873: /* block too small */
1.24 ! snw 2874: if ((offset - j) > DATALIM) splitp (filedes, block, &addr, &offset, &blknbr);
1.1 snw 2875:
2876: i = offset;
2877: offset -= j;
2878: j = offset;
2879: k = addr + oldkeyl;
2880:
2881: while (i > k) block[j--] = block[i--];
2882:
2883: }
2884:
2885: block[OFFS] = offset / 256;
2886: block[OFFS + 1] = offset % 256;
2887: block[addr] = keyl;
2888:
2889: /* overwrite */
2890: i = 0;
2891: j = (++addr);
2892: block[j++] = 0; /*!!! */
2893:
2894: while (i < keyl) block[j++] = ins_key[i++];
2895:
2896: /* block pointed to remains the same */
1.24 ! snw 2897: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2898: write (filedes, block, BLOCKLEN);
! 2899:
1.17 snw 2900: }
1.24 ! snw 2901:
! 2902: lseek (filedes, (long) blknbr * (long) (BLOCKLEN), 0);
! 2903: read (filedes, block, BLOCKLEN);
1.1 snw 2904:
2905: }
2906:
2907: return;
2908:
2909: } /* end of update() */
2910:
2911: /*
2912: * insert pointer
2913: * filedes: file descriptor
2914: * ins_key: key to be inserted
2915: * key_len: length of that key
2916: * blknbr: key points to this block
2917: */
1.24 ! snw 2918: static void insert (int filedes, char *ins_key, long key_len, unsigned long blknbr) /* insert pointer */
1.1 snw 2919: {
2920: unsigned long blk;
2921: char block[BLOCKLEN];
2922: long trxsav;
2923: long offset;
2924: long needed;
2925: long addr;
2926: register int i, k;
1.24 ! snw 2927:
1.1 snw 2928: trxsav = trx--;
2929: blk = traceblk[trx];
2930: addr = traceadr[trx];
2931:
1.24 ! snw 2932: lseek (filedes, (long) (blk) * (long) (BLOCKLEN), 0);
! 2933: read (filedes, block, BLOCKLEN);
1.1 snw 2934:
2935: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 2936: UNSIGN (block[OFFS + 1]);
1.1 snw 2937:
2938: if (traceadr[trx + 1] != (-1)) {
2939: addr += UNSIGN (block[addr]);
2940: addr += (2 + PLEN);
2941: } /* advance to next entry */
2942:
2943: needed = key_len + 2 + PLEN;
2944:
1.24 ! snw 2945: if ((offset + needed) > DATALIM) splitp (filedes, block, &addr, &offset, &blk);
1.1 snw 2946:
2947: /* insert key */
2948: i = (offset += needed);
2949:
2950: block[OFFS] = i / 256;
2951: block[OFFS + 1] = i % 256;
2952:
2953: while (i >= addr) {
2954: block[i] = block[i - needed];
2955: i--;
2956: }
2957:
2958: i = addr + 2;
2959: k = 0;
2960:
2961: while (k < key_len) block[i++] = ins_key[k++];
2962:
2963: block[addr] = k;
2964: block[addr + 1] = 0; /* !!! */
2965: block[i++] = blknbr / 65536;
2966: block[i++] = blknbr % 65536 / 256;
2967: block[i] = blknbr % 256;
2968:
1.24 ! snw 2969: lseek (filedes, (long) (blk) * (long) (BLOCKLEN), 0);
! 2970: write (filedes, block, BLOCKLEN);
1.1 snw 2971:
2972: trx = trxsav;
2973:
2974: return;
2975: } /* end of insert() */
2976:
2977: /*
2978: * mark 'blknbr' as free
2979: * filedes: global file descriptor
2980: * blknbr: block to be freed
2981: */
1.24 ! snw 2982: static void b_free (short filedes, unsigned long blknbr)
1.1 snw 2983: {
2984: char block0[BLOCKLEN];
2985: unsigned long free;
2986: unsigned long other;
2987: long i;
2988: long offset;
1.24 ! snw 2989:
1.17 snw 2990: /* mark block as empty */
1.24 ! snw 2991: lseek (filedes, (long) (blknbr) * BLOCKLEN, 0);
! 2992: read (filedes, block0, BLOCKLEN);
! 2993:
! 2994: block0[BTYP] = EMPTY;
1.9 snw 2995:
1.24 ! snw 2996: lseek (filedes, (long) (blknbr) * BLOCKLEN, 0);
! 2997: write (filedes, block0, BLOCKLEN);
1.1 snw 2998:
2999: /* do we have a list of free blocks? */
1.24 ! snw 3000: lseek (filedes, ROOT, 0);
! 3001: read (filedes, block0, BLOCKLEN);
1.1 snw 3002:
3003: if ((free = UNSIGN (block0[FREE]) * 65536 + UNSIGN (block0[FREE + 1]) * 256 + UNSIGN (block0[FREE + 2]))) {
3004:
3005: for (;;) {
1.24 ! snw 3006:
! 3007: lseek (filedes, (long) free * (long) BLOCKLEN, 0);
! 3008: read (filedes, block0, BLOCKLEN);
1.1 snw 3009:
3010: other = UNSIGN (block0[RLPTR]) * 65536 +
1.24 ! snw 3011: UNSIGN (block0[RLPTR + 1]) * 256 +
! 3012: UNSIGN (block0[RLPTR + 2]);
1.1 snw 3013:
3014: if (other == 0) break;
3015:
3016: free = other;
3017:
3018: }
3019:
3020: offset = UNSIGN (block0[OFFS]) * 256 + UNSIGN (block0[OFFS + 1]);
3021:
3022: /* if list is full, start new page */
3023: if (offset > (DATALIM - PLEN)) {
3024:
3025: offset -= PLEN;
3026: other = UNSIGN (block0[offset]) * 65536 +
3027:
1.24 ! snw 3028: UNSIGN (block0[offset + 1]) * 256 +
! 3029: UNSIGN (block0[offset + 2]);
1.1 snw 3030:
3031: block0[offset] = 0;
3032: block0[offset + 1] = 0;
3033: block0[offset + 2] = 0;
3034: block0[OFFS] = offset / 256;
3035: block0[OFFS + 1] = offset % 256;
3036: block0[RLPTR] = other / 65536;
3037: block0[RLPTR + 1] = other % 65536 / 256;
3038: block0[RLPTR + 2] = other % 256;
1.24 ! snw 3039:
! 3040: lseek (filedes, (long) free * (long) BLOCKLEN, 0);
! 3041: write (filedes, block0, BLOCKLEN);
1.1 snw 3042:
3043: for (i = 0; i < BLOCKLEN; block0[i++] = 0); /* clear block */
3044:
3045: block0[BTYP] = FBLK;
3046: block0[LLPTR] = free / 65536;
3047: block0[LLPTR + 1] = free % 65536 / 256;
3048: block0[LLPTR + 2] = free % 256;
3049: offset = 0;
3050:
3051: free = other;
3052:
3053: }
3054:
3055: }
3056: else {
1.24 ! snw 3057:
! 3058: getnewblk (filedes, &free);
1.1 snw 3059:
3060: /* set FBLK free blocks pointer */
1.24 ! snw 3061: lseek (filedes, ROOT, 0);
! 3062: read (filedes, block0, BLOCKLEN);
1.1 snw 3063:
3064: block0[FREE] = free / 65536;
3065: block0[FREE + 1] = free % 65536 / 256;
3066: block0[FREE + 2] = free % 256;
1.24 ! snw 3067:
! 3068: lseek (filedes, ROOT, 0);
! 3069: write (filedes, block0, BLOCKLEN);
1.1 snw 3070:
3071: for (i = 0; i < BLOCKLEN; block0[i++] = 0); /* clear block */
3072:
3073: block0[BTYP] = FBLK;
3074: offset = 0;
3075: }
3076:
3077: /* enter 'blknbr' */
3078: block0[offset++] = blknbr / 65536;
3079: block0[offset++] = blknbr % 65536 / 256;
3080: block0[offset++] = blknbr % 256;
3081: block0[OFFS] = offset / 256;
3082: block0[OFFS + 1] = offset % 256;
3083:
1.24 ! snw 3084: lseek (filedes, (long) free * (long) BLOCKLEN, 0);
! 3085: write (filedes, block0, BLOCKLEN);
1.1 snw 3086:
3087: return;
3088: } /* end of b_free() */
3089:
3090: /*
3091: * scan pointer 'block' for 'compactkey'
3092: *
3093: * 'adr' will return an adress
3094: * 2 heureka; key found at adr
3095: * 1 not found, adr=following entry
3096: */
3097: static void scanpblk (char *block, long *adr, long *fnd)
3098: {
3099: register int i = 0;
3100: register int k;
3101: long j, offset, len;
3102: char key0[256];
3103:
3104: *adr = 0;
3105: offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
3106:
3107: while (i < offset) {
3108:
3109: #ifdef VERSNEW
3110:
3111: j = i; /* save adress of current entry */
3112: len = UNSIGN (block[i++]);
3113:
3114: stcpy0 (key0, &block[++i], len);
3115:
3116: key0[len] = g_EOL;
3117: i += len;
3118:
3119: #else
3120:
3121: j = i++;
3122: len = UNSIGN (block[j]);
3123: k = 0;
3124: i++;
3125:
3126: while (k < len) key0[k++] = block[i++];
3127:
3128: key0[k] = g_EOL;
3129:
3130: #endif /* VERSNEW */
3131:
3132: if (((*fnd) = g_collate (key0)) == 1) return;
3133:
3134: *adr = j;
3135:
3136: if ((*fnd) == 2) return;
3137:
3138: i += PLEN;
3139:
3140: }
3141:
3142: return;
3143:
3144: } /* end of scanpblk() */
3145:
3146: /*
3147: * scan 'block' for 'compactkey'
3148: * same stuff as scanpblk for the params.
3149: */
3150: static void scandblk (char *block, long *adr, long *fnd)
3151: {
3152: register int i = 0;
3153: register int k;
3154: long offset, len;
3155: char key0[256];
3156:
3157: offset = UNSIGN (block[OFFS]) * 256 +
1.24 ! snw 3158: UNSIGN (block[OFFS + 1]);
1.1 snw 3159:
3160: while (i < offset) {
3161:
3162: #ifdef VERSNEW
3163:
3164: *adr = i;
3165:
3166: len = UNSIGN (block[i++]);
3167: k = UNSIGN (block[i++]);
3168:
3169: stcpy0 (&key0[k], &block[i], len);
3170:
3171: key0[k + len] = g_EOL;
3172: i += len;
3173:
3174: #else
3175:
3176: *adr = i++;
3177:
3178: len = UNSIGN (block[*adr]) + (k = UNSIGN (block[i++]));
3179:
3180: while (k < len) key0[k++] = block[i++];
3181:
3182: key0[k] = g_EOL;
3183:
3184: #endif /* VERSNEW */
3185:
3186: if (((*fnd) = g_collate (key0)) != 0) return;
3187:
3188: i += UNSIGN (block[i]);
3189:
3190: i++; /* skip data */
3191:
3192: }
3193:
3194: *adr = i;
3195:
3196: return;
3197:
3198: } /* end of scandblk() */
3199:
3200: /*
3201: * get a new block
3202: * filedes: global file descriptor
3203: * blknbr: number of new block
3204: */
1.24 ! snw 3205: static void getnewblk (int filedes, unsigned long *blknbr)
1.1 snw 3206: {
3207: char nblock[BLOCKLEN];
3208: unsigned long freeblks, no_of_blks;
3209: long other;
3210: long offset;
3211:
1.24 ! snw 3212: lseek (filedes, ROOT, 0);
! 3213: read (filedes, nblock, BLOCKLEN);
1.1 snw 3214:
3215: freeblks = UNSIGN (nblock[FREE]) * 65536 + UNSIGN (nblock[FREE + 1]) * 256 + UNSIGN (nblock[FREE + 2]);
3216: no_of_blks = UNSIGN (nblock[NRBLK]) * 65536 + UNSIGN (nblock[NRBLK + 1]) * 256 + UNSIGN (nblock[NRBLK + 2]);
3217:
3218: if (freeblks) {
1.24 ! snw 3219:
! 3220: lseek (filedes, (long) (freeblks) * BLOCKLEN, 0);
! 3221: read (filedes, nblock, BLOCKLEN);
1.1 snw 3222:
3223: offset = UNSIGN (nblock[OFFS]) * 256 + UNSIGN (nblock[OFFS + 1]);
3224:
3225: if (offset == 0) { /* free list is empty. return free list blk as new block. */
3226:
3227: *blknbr = freeblks;
3228: other = UNSIGN (nblock[RLPTR]) * 65536 + UNSIGN (nblock[RLPTR + 1]) * 256 + UNSIGN (nblock[RLPTR + 2]);
3229:
3230: /* update RL-block, if any */
3231: if (other) {
3232:
1.24 ! snw 3233: lseek (filedes, (long) (other) * BLOCKLEN, 0);
! 3234: read (filedes, nblock, BLOCKLEN);
1.1 snw 3235:
3236: nblock[LLPTR] = 0;
3237: nblock[LLPTR + 1] = 0;
3238: nblock[LLPTR + 2] = 0;
1.24 ! snw 3239:
! 3240: lseek (filedes, (long) (other) * BLOCKLEN, 0);
! 3241: write (filedes, nblock, BLOCKLEN);
1.1 snw 3242:
3243: }
3244:
3245: /* update ROOT block */
1.24 ! snw 3246: lseek (filedes, ROOT, 0);
! 3247: read (filedes, nblock, BLOCKLEN);
1.1 snw 3248:
3249: nblock[FREE] = other / 65536;
3250: nblock[FREE + 1] = other % 65536 / 256;
3251: nblock[FREE + 2] = other % 256;
1.24 ! snw 3252:
! 3253: lseek (filedes, ROOT, 0);
! 3254: write (filedes, nblock, BLOCKLEN);
1.1 snw 3255:
3256: return;
3257:
3258: }
3259:
3260: offset -= PLEN;
3261: *blknbr = UNSIGN (nblock[offset]) * 65536 + UNSIGN (nblock[offset + 1]) * 256 + UNSIGN (nblock[offset + 2]);
3262: nblock[offset] = 0;
3263: nblock[offset + 1] = 0;
3264: nblock[OFFS] = offset / 256;
3265: nblock[OFFS + 1] = offset % 256;
1.24 ! snw 3266:
! 3267: lseek (filedes, (long) (freeblks) * BLOCKLEN, 0);
! 3268: write (filedes, nblock, BLOCKLEN);
1.1 snw 3269:
3270: return;
3271:
3272: }
3273:
3274: /* else ** freeblk==0 ** */
3275: no_of_blks++;
3276: nblock[NRBLK] = no_of_blks / 65536;
3277: nblock[NRBLK + 1] = no_of_blks % 65536 / 256;
3278: nblock[NRBLK + 2] = no_of_blks % 256;
1.24 ! snw 3279:
! 3280: lseek (filedes, ROOT, 0);
! 3281: write (filedes, nblock, BLOCKLEN);
1.1 snw 3282:
3283: *blknbr = no_of_blks;
1.24 ! snw 3284:
! 3285: for (;;) {
! 3286:
! 3287: errno = 0;
! 3288:
! 3289: lseek (filedes, (long) (no_of_blks) * BLOCKLEN, 0);
! 3290: write (filedes, nblock, BLOCKLEN);
! 3291:
! 3292: if (errno == 0) break;
! 3293:
! 3294: panic ();
1.1 snw 3295:
1.24 ! snw 3296: }
1.1 snw 3297:
3298: return;
3299:
3300: } /* end of getnewblk() */
3301:
3302: /*
3303: * return TRUE if 't' follows 'compactkey' in MUMPS collating sequence
3304: */
3305: static short int g_collate (char *t)
3306: {
3307: char *s = compactkey;
3308: register int chs = *s;
3309: register int cht = *t;
3310: register int tx = 0;
3311: register int sx;
3312: short dif;
3313:
3314: /* the empty one is the leader! */
3315: if (chs == g_EOL) {
3316:
3317: if (cht == g_EOL) return 2;
3318:
3319: return TRUE;
3320:
3321: }
3322:
3323: if (cht == g_EOL) return FALSE;
3324:
3325: while (cht == s[tx]) {
3326:
3327: if (cht == g_EOL) return 2;
3328:
3329: cht = t[++tx];
3330:
3331: } /* (s==t) */
3332:
3333: chs = s[tx];
3334:
3335: if (chs == OMEGA) return FALSE;
3336: if (chs == ALPHA) return cht != g_EOL;
3337: if (chs == g_EOL && t[tx - 1] & 01) return TRUE;
3338: if (cht == g_EOL && s[tx - 1] & 01) return FALSE;
3339:
3340: if (tx > 0) {
3341:
3342: tx--;
3343:
3344: while ((t[tx] & 01) == 0) {
3345:
3346: tx--;
3347:
3348: if (tx < 0) break;
3349:
3350: }
3351:
3352: tx++;
3353:
3354: }
3355:
3356: chs = s[tx];
3357: cht = t[tx];
3358:
3359: if (UNSIGN (chs) <= POINT) { /* then come numerics */
3360:
3361: if (UNSIGN (cht) > POINT) return UNSIGN (cht) != g_EOL;
3362:
3363: /* both are numeric! now compare numeric values */
3364:
3365: if (chs == MINUS) {
3366: if (cht != MINUS) return TRUE;
3367: }
3368: else {
3369: if (cht == MINUS) return FALSE;
3370: }
3371:
3372: if (chs == 1 && cht == POINT) return TRUE;
3373: if (cht == 1 && chs == POINT) return FALSE;
3374:
3375: dif = sx = tx;
3376:
3377: while (s[sx] != POINT) {
3378: if (s[sx++] & 01) break;
3379: }
3380:
3381: while (t[tx] != POINT) {
3382: if (t[tx++] & 01) break;
3383: }
3384:
3385: if (tx > sx) return cht != MINUS;
3386: if (tx < sx) return cht == MINUS;
3387:
3388: tx = dif;
3389: while ((cht >> 1) == (chs >> 1)) {
3390:
3391: if (cht & 01) return t[dif] == MINUS;
3392: if (chs & 01) return t[dif] != MINUS;
3393:
3394: chs = s[++tx];
3395: cht = t[tx];
3396:
3397: }
3398:
3399: return (((cht >> 1) > (chs >> 1)) == (t[dif] != MINUS)) && (t[tx] != s[tx]);
3400:
3401: }
3402:
3403: if (UNSIGN (cht) <= POINT) return FALSE;
3404:
3405: while ((dif = (UNSIGN (cht) >> 1) - (UNSIGN (chs) >> 1)) == 0) { /* ASCII collating */
3406:
3407: if ((cht & 01) && ((chs & 01) == 0)) return FALSE;
3408: if ((chs & 01) && ((cht & 01) == 0)) return TRUE;
3409:
3410: chs = s[++tx];
3411: cht = t[tx];
3412:
3413: }
3414:
3415: if (chs == g_EOL) return TRUE;
3416: if (cht == g_EOL) return FALSE;
3417:
3418: return dif > 0;
3419:
3420: } /* end g_collate() */
3421:
3422: /*
3423: * test whether 'str' is canonical
3424: */
1.24 ! snw 3425: //static short int g_numeric (char *str)
1.1 snw 3426: short g_numeric (char *str)
3427: {
3428: register int ptr = 0, ch;
3429: register int point = 0;
3430:
3431: if (str[0] == '-') {
3432: if ((ch = str[++ptr]) == EOL || (ch == DELIM) || (ch == '0')) return FALSE;
3433: }
3434: else if (str[0] == '0') {
3435:
3436: if ((ch = str[ptr + 1]) == EOL || ch == DELIM) return TRUE;
3437:
3438: return FALSE; /* leading zero */
3439: }
3440:
3441: while ((ch = str[ptr++]) != EOL && ch != DELIM) {
3442:
3443: if (ch > '9') return FALSE;
3444:
3445: if (ch < '0') {
3446:
3447: if (ch != '.') return FALSE;
3448: if (point) return FALSE; /* multiple points */
3449:
3450: point = TRUE;
3451:
3452: }
3453:
3454: }
3455:
3456: if (point) {
3457:
3458: ch = str[ptr - 2];
3459:
3460: if (ch == '0' || ch == '.') return FALSE;
3461:
3462: }
3463:
3464: return TRUE;
3465:
3466: } /* end g_numeric() */
3467:
3468: void close_all_globals (void)
3469: {
1.24 ! snw 3470: register int i;
! 3471:
! 3472: for (i = 0; i < NO_GLOBLS; i++) {
! 3473:
! 3474: if (oldfil[i][0] != NUL) {
! 3475:
! 3476: close (olddes[i]);
! 3477:
! 3478: usage[i] = 0;
! 3479: olddes[i] = 0;
! 3480: oldfil[i][0] = NUL;
! 3481:
! 3482: }
! 3483:
! 3484: }
! 3485:
1.1 snw 3486: return;
1.24 ! snw 3487:
! 3488: } /* end close_all_globals() */
1.1 snw 3489:
3490: static void panic (void)
1.24 ! snw 3491: {
! 3492: printf ("\033[s\033[25H\033[5;7mwrite needs more disk space immediately\007");
! 3493: sleep (1);
! 3494: printf ("\033[m\007\033[2K\033[u");
! 3495:
! 3496: /* restore screen 'cause system messed up screen */
! 3497:
! 3498: #ifdef NOWRITEM
! 3499:
! 3500: write_m ("\033[4~\201");
! 3501:
! 3502: #endif /* NOWRITEM */
! 3503:
1.1 snw 3504: return;
1.24 ! snw 3505:
! 3506: } /* end panic() */
1.1 snw 3507:
3508:
3509: void gbl_dump_stat(void)
3510: {
1.24 ! snw 3511: register int i;
! 3512:
! 3513: printf ("FreeM Global Statistics [PID %d]\r\n", pid);
! 3514:
! 3515: printf ("%-10s%-20s%s\r\n", "USECT", "AGE", "FILE");
! 3516: printf ("%-10s%-20s%s\r\n", "=====", "===", "====");
! 3517:
! 3518: for (i = 0; i < NO_GLOBLS; i++) {
! 3519: printf ("%-10d%-20ld%s\r\n", usage[i], g_ages[i], oldfil[i]);
! 3520: }
1.18 snw 3521:
1.1 snw 3522: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>