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