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