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