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