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