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