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