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