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