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