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