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