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