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