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