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