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