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