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