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