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