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