Annotation of freem/src/fma_globals.c, revision 1.6
1.1 snw 1: /*
1.6 ! snw 2: * $Id: fma_globals.c,v 1.5 2025/03/22 18:43:54 snw Exp $
1.1 snw 3: * fmadm - globals
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: fma_globals.c,v $
1.6 ! snw 27: * Revision 1.5 2025/03/22 18:43:54 snw
! 28: * Make STRLEN 255 chars and add BIGSTR macro for larger buffers
! 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 <stdlib.h>
39: #include <stdio.h>
40: #include <stdlib.h>
41: #include <string.h>
42: #include <dirent.h>
43: #include <time.h>
44: #include <unistd.h>
45: #include <sys/types.h>
46: #include <sys/stat.h>
47: #include <fcntl.h>
48:
49: #include "fmadm.h"
50:
51: void gl (char *global, short kf, short df, short nr, int chop);
52: int gverify (char *gpath);
1.6 ! snw 53: /*static short int g_collate ();*/ /* if 't' follows 's' in MUMPS collating */
1.1 snw 54: int key_check (char *key);
1.2 snw 55: void check (unsigned long blknbr);
56: static short int g_collate (char s[], char t[]); /* if 't' follows 's' in MUMPS collating */
57: void show (char key[]);
1.1 snw 58:
59: /* global variables for gverify */
60: short filedes; /* file descriptor */
61: char block[MAXLEV][BLOCKLEN]; /* block to be read */
62: char *blck; /* dto. as pointer */
63: unsigned long llink[MAXLEV]; /* left link pointers */
64: unsigned long rlink[MAXLEV]; /* right link pointers */
65: short offsets[MAXLEV]; /* offsets */
66: short type[MAXLEV]; /* block type */
67: extern short level; /* current level */
68: unsigned long no_of_blks; /* number of blocks */
69: unsigned long freeblks; /* free blocks list */
70: char key[256]; /* current key in pointer block scan */
71: short exstat = 0; /* exit status */
72: void showpath (); /* display path of pointers */
73: /* end of global variables for gverify */
74:
75:
76: int fma_globals_list (int optc, char **opts)
77: {
78: DIR *dir;
79: struct dirent *ent;
80:
1.5 snw 81: char filename[PATHLEN];
1.1 snw 82:
83: int ct = 0;
84:
85: printf ("\nFreeM Global Listing\n");
86: printf ("--------------------\n\n");
87:
88: printf ("Namespace: %s\n", fma_namespace);
89: printf ("Global Path: %s\n\n", fma_global_path);
90:
91: if ((dir = opendir (fma_global_path)) == NULL) {
92: fprintf (stderr, "fmadm: could not open global directory %s\n", fma_global_path);
93: return 1;
94: }
95:
96: while ((ent = readdir (dir)) != NULL) {
97:
1.5 snw 98: strncpy (filename, ent->d_name, PATHLEN - 1);
1.1 snw 99:
100: if (filename[0] == '^' && filename[1] != '$') {
101: printf (" %s\n", filename);
102: ct++;
103: }
104:
105: }
106:
107: printf ("\n\n - %d globals found\n\n", ct);
108: closedir (dir);
109:
110: return 0;
111: }
112:
113: int fma_globals_examine (int optc, char **opts)
114: {
115:
116: DIR *dir;
117: struct dirent *ent;
118:
1.5 snw 119: char gpath[PATHLEN];
1.1 snw 120: int i;
121: int ct = 0;
122:
123: if ((dir = opendir (fma_global_path)) == NULL) {
124: fprintf (stderr, "fmadm: could not open global directory %s\n", fma_global_path);
125: return 1;
126: }
127:
128: printf ("\nFreeM Global Examine\n");
129: printf ("--------------------\n\n");
130:
131: printf ("Namespace: %s\n", fma_namespace);
132: printf ("Global Path: %s\n", fma_global_path);
133: printf ("Globals Selected: ");
134:
135:
136: if (optc > 1) {
137:
138: for (i = fma_base_opt; i <= optc; i++) {
139: printf ("%s ", opts[i]);
140: }
141:
142: printf ("\n\n");
143:
144: }
145: else {
146: printf ("[ENTIRE NAMESPACE]\n\n");
147: }
148:
149:
150: if (optc > 1) {
151:
152: for (i = fma_base_opt; i < optc; i++) {
153:
1.5 snw 154: snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);
1.1 snw 155: gl (gpath, FALSE, FALSE, FALSE, strlen (fma_global_path));
156:
157: ct++;
158:
159: }
160:
161: }
162: else {
163:
164: while ((ent = readdir (dir)) != NULL) {
165:
1.5 snw 166: strncpy (gpath, ent->d_name, PATHLEN - 1);
1.1 snw 167:
168: if (gpath[0] == '^' && gpath[1] != '$') {
169:
1.5 snw 170: snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, ent->d_name);
1.1 snw 171:
172: gl (gpath, FALSE, FALSE, FALSE, strlen (fma_global_path));
173:
174: ct++;
175:
176: }
177:
178: }
179:
180: }
181:
182: printf ("\n\n");
183: printf (" - %d globals examined\n\n", ct);
184:
185: return 0;
186:
187: }
188:
189: int fma_globals_remove (int optc, char **opts)
190: {
191:
1.5 snw 192: char gpath[PATHLEN];
1.1 snw 193: int i;
194: int ct = 0;
195: int er = 0;
196: int tot = 0;
197:
198: printf ("\nFreeM Global Removal\n");
199: printf ("--------------------\n\n");
200:
201: printf ("Namespace: %s\n", fma_namespace);
202: printf ("Global Path: %s\n\n", fma_global_path);
203:
204: for (i = fma_base_opt; i < optc; i++) {
205: printf ("%-10s\t", opts[i]);
206:
1.5 snw 207: snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);
1.1 snw 208:
209: if (unlink (gpath) == -1) {
210: printf ("[FAIL]\n");
211: er++;
212: }
213: else {
214: printf ("[OK]\n");
215: ct++;
216: }
217:
218: tot++;
219:
220: }
221:
222: printf ("\nRemoved %d globals [%d errors/%d attempted]\n\n", ct, er, tot);
223:
224: return 0;
225:
226: }
227:
228: int fma_globals_verify (int optc, char **opts)
229: {
230: DIR *dir;
231: struct dirent *ent;
232:
1.5 snw 233: char gpath[PATHLEN];
1.1 snw 234: int i;
235: int ct = 0;
236:
237: if ((dir = opendir (fma_global_path)) == NULL) {
238: fprintf (stderr, "fmadm: could not open global directory %s\n", fma_global_path);
239: return 1;
240: }
241:
242: printf ("\nFreeM Global Verify\n");
243: printf ("-------------------\n\n");
244:
245: printf ("Namespace: %s\n", fma_namespace);
246: printf ("Global Path: %s\n", fma_global_path);
247: printf ("Globals Selected: ");
248:
249: if (optc > fma_base_opt) {
250:
251: for (i = fma_base_opt; i < optc; i++) {
252: printf ("%s ", opts[i]);
253: }
254:
255: printf ("\n\n");
256:
257: }
258: else {
259: printf ("[ENTIRE NAMESPACE]\n\n");
260: }
261:
262:
263: if (optc > fma_base_opt) {
264:
265: for (i = fma_base_opt; i < optc; i++) {
266:
1.5 snw 267: snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);
1.1 snw 268:
269: exstat = 0;
270: gverify (gpath);
271:
272: printf ("\n\t%d error(s) in %s\n", exstat, gpath);
273:
274: ct++;
275:
276: }
277:
278: }
279: else {
280:
281: while ((ent = readdir (dir)) != NULL) {
282:
1.5 snw 283: strncpy (gpath, ent->d_name, PATHLEN - 1);
1.1 snw 284:
285: if (gpath[0] == '^') {
286:
1.5 snw 287: snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, ent->d_name);
1.1 snw 288:
289: exstat = 0;
290: gverify (gpath);
291:
292: printf ("\n\t%d errors in %s\n", exstat, gpath);
293:
294: ct++;
295:
296: }
297:
298: }
299:
300: }
301:
302: printf ("\n\n");
303: printf (" - %d globals verified\n\n", ct);
304:
305: return 0;
306:
307: }
308:
309:
310: /* PRIVATE FUNCTIONS */
311:
312: /***
313: * gl(): list global
314: *
315: * global: name of global
316: * kf: key flag
317: * df: data flag
318: * nr: naked reference flag
319: */
320: void gl (char *global, short kf, short df, short nr, int chop)
321: {
322: short filedes; /* file descriptor */
323: char block[BLOCKLEN]; /* block to be read */
324: char key[512];
325: char prevkey[512]; /* previous key */
326: char data[1024]; /* if data has CTRLs it may become */
327: /* so long */
328: unsigned long blknbr;
329: short offset;
330: short length;
331: short koffs;
332: short dkf = TRUE;
333:
334: short CtrlFlag;
335: short n, k1;
336: register int i, j, k, ch;
337:
338: if ((filedes = open (global, 0)) == -1) {
339: printf ("%s: cannot open\012\015", global);
340:
341: return;
342: }
343:
344: if (kf == FALSE && df == FALSE) {
345: kf = TRUE;
346: df = TRUE;
347: }
348: else {
349: dkf = FALSE;
350: }
351:
352: blknbr = ROOT;
353: prevkey[0] = 0;
354: prevkey[1] = 0;
355: prevkey[2] = 0;
356:
357: for (;;) {
358:
359: lseek (filedes, blknbr * BLOCKLEN, 0);
360:
361: if (read (filedes, block, BLOCKLEN) == 0) {
362: fprintf (stderr, "\015*** something wrong ***\033[K\n\r");
363: exit (0);
364: }
365:
366: if (block[BTYP] == DATA) goto first;
367:
368: i = UNSIGN (block[0]) + 2;
369: blknbr = UNSIGN (block[i]) * 65536 + UNSIGN (block[i + 1]) * 256 + UNSIGN (block[i + 2]);
370:
371: }
372:
373: again:
374:
375: if (blknbr == 0) {
376: close (filedes);
377: return;
378: }
379:
380: lseek (filedes, blknbr * 1024L, 0);
381: read (filedes, block, BLOCKLEN);
382:
383: first:
384:
385: offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
386: blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]);
387:
388: i = 0;
389: while (i < offset) {
390:
391: length = UNSIGN (block[i++]);
392: k = koffs = UNSIGN (block[i++]);
393:
394: if ((i + length) > offset) break;
395:
396: for (j = 0; j < length; j++) key[k++] = block[i++];
397:
398: key[k] = g_EOL;
399: {
400:
401: short ch0, i, j, k;
402:
403: j = 0;
404: i = 0;
405: data[j++] = '(';
406: k = 1;
407:
408: while ((ch = UNSIGN (key[i++])) != g_EOL) {
409:
410: if (k) {
411: k = 0;
412: if (ch > SP) data[j++] = '"';
413: }
414:
415: ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
416: (ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
417: (ch >> 1) + SP)); /* '.' or '-' */
418:
419: if (ch0 == DEL) {
420: if ((ch0 = (UNSIGN (key[i++]) >> 1)) == DEL) {
421: ch0 = (UNSIGN (key[i++]) >> 1) + DEL;
422: }
423:
424: ch0 += DEL;
425: data[j] = '<';
426: data[++j] = '0' + ch0 / 100;
427: data[++j] = '0' + (ch0 % 100) / 10;
428: data[++j] = '0' + ch0 % 10;
429: data[++j] = '>';
430:
431: }
432: else {
433: data[j] = ch0;
434: }
435:
436: if (data[j++] == '"') data[j++] = '"';
437:
438: if (ch & 01) {
439:
440: if (ch > SP) data[j++] = '"';
441:
442: data[j++] = ',';
443: k = 1;
444:
445: }
446:
447: }
448:
449: data[j--] = 0;
450: data[j] = ')';
451:
452: if (j == 0) data[0] = 0;
453:
454: while (j >= 0) {
455: if ((ch = data[--j]) < SP || ch >= DEL) break;
456: }
457:
458: k1 = 0;
459: if (nr) {
460:
461: if (prevkey[0]) {
462:
463: n = ch = 0;
464:
465: while (data[n] == prevkey[n]) {
466:
467: if (prevkey[n] == '"') ch = !ch;
468: if (!ch && k1 == 0 && (prevkey[n] == '(')) k1 = n + 1;
469: if (!ch && (prevkey[n] == ',')) k1 = n + 1;
470:
471: n++;
472:
473: }
474:
475: while (prevkey[n]) {
476:
477: if (prevkey[n] == '"') ch = !ch;
478:
479: if (!ch && (prevkey[n] == ',')) {
480: k1 = 0;
481: break;
482: }
483:
484: n++;
485:
486: }
487:
488: }
489:
490: strcpy (prevkey, data);
491:
492: if (k1 > 1) {
493: strcpy (&data[1], &data[k1]);
494: }
495:
496: }
497:
498: if (j < 0) {
499:
500: if (kf) {
501:
502: if (k1) {
503: printf ("%c%s", '^', data);
504: }
505: else {
506: printf ("%s%s", global + chop + 1, data);
507: }
508:
509: }
510:
511: if (dkf && !nr) {
512: printf ("=");
513: }
514: else if (kf) {
515: printf ("\n");
516: }
517:
518: }
519: else {
520: fprintf (stderr, "[%d][%d] <illegal subscript>\n", length, koffs);
521: }
522:
523: }
524:
525: length = UNSIGN (block[i++]);
526:
527: stcpy0 (data, &block[i], (long) length);
528:
529: data[length] = EOL;
530:
531: if (numeric (data)) {
532: data[length] = 0;
533: i += length;
534: }
535: else {
536:
537: CtrlFlag = 0;
538: data[0] = '"';
539: k = 1;
540:
541: while (length-- > 0) {
542:
543: ch = UNSIGN (block[i++]);
544:
545: if ((ch >= SP) && (ch < DEL)) {
546:
547: if (CtrlFlag) { /* close Bracket after CTRL */
548:
549: data[k++] = ')';
550: data[k++] = '_';
551: data[k++] = '"';
552:
553: CtrlFlag = 0;
554:
555: }
556:
557: if ((data[k++] = ch) == '"') data[k++] = ch;
558:
559: }
560: else {
561:
562: if (((ch >= NUL) && (ch < SP)) || ch == DEL) {
563:
564: if (CtrlFlag) {
565: data[k++] = ',';
566: }
567: else {
568:
569: if (k > 1) {
570: data[k++] = '"';
571: data[k++] = '_';
572: }
573: else {
574: k = 0;
575: }
576:
577: data[k++] = '$';
578: data[k++] = 'C';
579: data[k++] = '(';
580:
581: CtrlFlag = 1;
582:
583: }
584:
585: if (ch == DEL) {
586: data[k++] = '1';
587: ch -= 100;
588: }
589:
590: if (ch >= 10) {
591: data[k++] = ch / 10 + '0';
592: ch = ch % 10;
593: }
594:
595: data[k++] = ch + '0';
596:
597: }
598: else {
599:
600: if (CtrlFlag) { /* close Bracket after CTRL */
601:
602: data[k++] = ')';
603: data[k++] = '_';
604: data[k++] = '"';
605:
606: CtrlFlag = 0;
607:
608: }
609:
610: data[k++] = '<';
611:
612: if (ch > 99) {
613: data[k++] = '0' + (ch / 100);
614: ch = ch % 100;
615: }
616:
617: if (ch > 9) {
618: data[k++] = '0' + (ch / 10);
619: ch = ch % 10;
620: }
621:
622: data[k++] = '0' + ch;
623: data[k++] = '>';
624:
625: }
626: }
627: }
628:
629: if (CtrlFlag) {
630: data[k++] = ')';
631: }
632: else {
633: data[k++] = '"';
634: }
635:
636: data[k] = 0;
637:
638: }
639:
640: if (df) printf ("%s\n", data);
641:
642: }
643:
644: if (i != offset) fprintf (stderr, "\nwrong offset %d vs. %d\n", offset, i);
645:
646: goto again;
647:
648: }
649:
650: int gverify (char *gpath)
651: {
652: register int j;
653:
654: printf ("\n%s:\n\n", gpath);
655:
656: if ((filedes = open (gpath, 0)) == -1) {
657: fprintf (stderr, "Cannot open file %s\007\n\r", gpath);
658: return 1;
659: }
660:
661: j = 0;
662:
663: while (j < MAXLEV) {
664:
665: rlink[j] = 0;
666: llink[j] = 0;
667:
668: j++;
669:
670: }
671:
672: level = 0;
673:
674: check (ROOT);
675:
676: j = 1; /* ignore level zero: there is no rightlink pointer (freeblocks instead) */
677: while (j < MAXLEV) { /* check last right link pointers (all zero!) */
678:
679: if (rlink[j] != 0) {
680: printf ("\tblock #%ld right link pointer mismatch 0 vs. %ld\012\015", llink[j], rlink[j]);
681: showpath ();
682: }
683:
684: j++;
685:
686: }
687:
688: /* check free blocks */
689: freeblks = UNSIGN (block[0][FREE]) * 65536 +
690: UNSIGN (block[0][FREE + 1]) * 256 +
691: UNSIGN (block[0][FREE + 2]);
692:
693: while (freeblks) {
694:
695: unsigned long free;
696: int i;
697:
698: if (freeblks > no_of_blks) {
699: printf ("\tblock# %ld (free list) greater than number of blocks (%ld)\012\015", freeblks, no_of_blks);
700: showpath ();
701: }
702:
703: lseek (filedes, (long) (freeblks) * BLOCKLEN, 0);
704:
705: if (read (filedes, block[0], BLOCKLEN) < BLOCKLEN) {
706:
707: printf ("\tblock #%ld is (partially) empty\012\015", freeblks);
708: showpath ();
709:
710: exit (exstat);
711:
712: }
713:
714: j = UNSIGN (block[0][OFFS]) * 256 +
715: UNSIGN (block[0][OFFS + 1]); /* offset */
716:
717: freeblks = UNSIGN (block[0][RLPTR]) * 65536 +
718: UNSIGN (block[0][RLPTR + 1]) * 256 +
719: UNSIGN (block[0][RLPTR + 1]);
720:
721: i = 0;
722:
723: while (i < j) {
724:
725: free = UNSIGN (block[0][i++]) * 65536;
726: free += UNSIGN (block[0][i++]) * 256;
727: free += UNSIGN (block[0][i++]);
728:
729: if (free > no_of_blks) {
730: printf ("\tblock #%ld (free) greater than number of blocks (%ld)\012\015", free, no_of_blks);
731: showpath ();
732: }
733:
734: lseek (filedes, free * BLOCKLEN, 0);
735: read (filedes, block[1], BLOCKLEN);
736:
737: if (block[1][BTYP] != EMPTY) {
738:
739: printf ("\tblock #%ld expected block type: EMPTY\012\015", free);
740:
741: if (++exstat >= ERRLIM) {
742: fprintf (stderr, "Error limit exceeded\012\015");
743: return exstat;
744: }
745:
746: }
747:
748: }
749:
750: }
751:
752: return exstat;
753:
754: }
755:
756: void check (unsigned long blknbr)
757: {
758: unsigned long left; /* current left link pointer */
759: unsigned long right; /* current right link pointer */
760: long i;
761: long k;
762:
763: lseek (filedes, blknbr * BLOCKLEN, 0);
764: blck = block[level];
765:
766: if (read (filedes, blck, BLOCKLEN) < BLOCKLEN) {
767: printf ("\tblock #%ld is (partially) empty\012\015", blknbr);
768: showpath ();
769: }
770:
771: type[level] = blck[BTYP];
772:
773: left = UNSIGN (blck[LLPTR]) * 65536 +
774: UNSIGN (blck[LLPTR + 1]) * 256 +
775: UNSIGN (blck[LLPTR + 2]);
776:
777: right = UNSIGN (blck[RLPTR]) * 65536 +
778: UNSIGN (blck[RLPTR + 1]) * 256 +
779: UNSIGN (blck[RLPTR + 2]);
780:
781: if (blknbr == ROOT) {
782: no_of_blks = UNSIGN (block[0][NRBLK]) * 65536 +
783: UNSIGN (block[0][NRBLK + 1]) * 256 +
784: UNSIGN (block[0][NRBLK + 2]);
785: }
786: else {
787:
788: if (blknbr > no_of_blks) {
789: printf ("\tblock# %ld greater than number of blocks (%ld)\012\015", blknbr, no_of_blks);
790: showpath ();
791: }
792:
793: }
794:
795: offsets[level] = UNSIGN (blck[OFFS]) * 256 + UNSIGN (blck[OFFS + 1]);
796:
797: if (rlink[level] != 0L && rlink[level] != blknbr) {
798: printf ("\tblock #%ld right link pointer mismatch %ld vs. %ld\012\015", llink[level], blknbr, rlink[level]);
799: showpath ();
800: }
801:
802: if (llink[level] != 0L && left != llink[level]) {
803: printf ("\tblock #%ld left link pointer mismatch %ld vs. %ld\012\015", blknbr, left, llink[level]);
804: showpath ();
805: }
806:
807: rlink[level] = right;
808: llink[level] = blknbr;
809:
810: if (blknbr != ROOT) {
811:
812: k = UNSIGN (blck[0]);
813: i = 0;
814:
815: while (i < k) {
816: if (blck[i + 2] != key[i]) {
817: printf ("\tblock #%ld first key mismatch to pointer block(%ld)\012\015", blknbr, llink[level - 1]);
818: showpath ();
819: break;
820: }
821: i++;
822: }
823:
824: }
825:
826: switch (type[level]) {
827:
828: case EMPTY:
829: printf ("\tblock #%ld unexpected block type: EMPTY\012\015", blknbr);
830: showpath ();
831: break;
832:
833: case FBLK:
834: printf ("\tblock #%ld unexpected block type: FBLK\012\015", blknbr);
835: showpath ();
836: break;
837:
838: case POINTER:
839: case BOTTOM:
840: /*******************************/
841: /* scan pointer block */
842: {
843: register long i;
844: register long k;
845: short j;
846: short len;
847: char key1[256];
848:
849: key1[0] = g_EOL;
850: i = 0;
851:
852: while (i < offsets[level]) {
853:
854: j = i++; /* save adress of current entry */
855:
856: if ((len = UNSIGN (blck[j]) + (k = UNSIGN (blck[i++]))) > 255) {
857: printf ("\tblock #%ld key too long\012\015", blknbr);
858: showpath ();
859: }
860: else {
861:
862: if (len == 0 && j) {
863: printf ("\tblock #%ld empty key\012\015", blknbr);
864: showpath ();
865: }
866:
867: while (k < len) key[k++] = blck[i++];
868:
869: key[k] = g_EOL;
870:
871: if (key_check (key)) {
872: printf ("\tblock #%ld illegal key\012\015", blknbr);
873: showpath ();
874: }
875:
876: if (g_collate (key1, key) == 0) {
877: printf ("\tblock #%ld collation mismatch\012\015", blknbr);
878: show (key1);
879: show (key);
880: showpath ();
881: }
882:
883: stcpy0 (key1, key, k + 1);
884: level++;
885:
886: check ((long) (UNSIGN (blck[i]) * 65536 +
887: UNSIGN (blck[i + 1]) * 256 +
888: UNSIGN (blck[i + 2])));
889:
890: blck = block[--level];
891:
892: }
893:
894: i += PLEN;
895:
896: if (i > DATALIM) {
897: printf ("\tblock #%ld pointer in status bytes\012\015", blknbr);
898: showpath ();
899: }
900:
901: }
902:
903: if (i > offsets[level]) {
904: printf ("\tblock #%ld offset mismatch %ld vs. %d\012\015", blknbr, i, offsets[level]);
905: showpath ();
906: }
907: }
908: break;
909:
910: case DATA:
911: /* scan data block */
912: {
913: register long i;
914: register long k;
915: short len;
916: char key0[256];
917: char key1[256];
918:
919: if (type[level - 1] != BOTTOM) {
920: printf ("\tblock #%ld unexpected block type: DATA\012\015", blknbr);
921: showpath ();
922: }
923:
924: key1[0] = g_EOL;
925: i = 0;
926:
927: while (i < offsets[level]) {
928:
929: len = UNSIGN (blck[i++]);
930: len += (k = UNSIGN (blck[i++]));
931:
932: if (len > 255) {
933: printf ("\tblock #%ld key too long\012\015", blknbr);
934: showpath ();
935: i += len - k;
936: }
937: else {
938:
939: if (len == 0 && i > 2) {
940: printf ("\tblock #%ld empty key\012\015", blknbr);
941: showpath ();
942: }
943:
944: while (k < len) key0[k++] = blck[i++];
945:
946: key0[k] = g_EOL;
947:
948: if (key_check (key0)) {
949: printf ("\tblock #%ld illegal key\012\015", blknbr);
950: showpath ();
951: }
952:
953: if (g_collate (key1, key0) == 0) {
954: printf ("\tblock #%ld collation mismatch\012\015", blknbr);
955: show (key1);
956: show (key0);
957: showpath ();
958: }
959:
960: stcpy0 (key1, key0, k + 1);
961: }
962:
963: k = i + 1;
964: len = UNSIGN (blck[i]);
965: i += UNSIGN (blck[i]);
966: i++; /* skip data */
967:
968: #ifdef NEVER
969: while (k < i) {
970: if (blck[k++] & ~0177) {
971: printf ("\tblock #%ld illegal character in data string\012\015", blknbr);
972: showpath ();
973: break;
974: }
975: }
976: #endif /* NEVER */
977:
978: if (i > DATALIM) {
979: printf ("\tblock #%ld data in status bytes\012\015", blknbr);
980: showpath ();
981: }
982:
983: }
984:
985: if (i > offsets[level]) {
986: printf ("\tblock #%ld offset mismatch %ld vs. %d\012\015", blknbr, i, offsets[level]);
987: showpath ();
988: }
989: }
990: break;
991:
992: default:
993: printf ("\tblock #%ld illegal type %d\012\015", blknbr, type[level]);
994: showpath ();
995:
996: }
997:
998: return;
999:
1000: } /* end check */
1001: void
1002: showpath ()
1003: { /* display path of pointers */
1004: int i;
1005:
1006: if (level > 1)
1007: for (i = 0; i < level; i++)
1008: printf (" path level(%d)=%ld\012\015", i, llink[i]);
1009: if (++exstat >= ERRLIM) {
1.2 snw 1010: fprintf (stderr, "Error limit exceeded (%hd errors)\012\015", exstat);
1.1 snw 1011: return;
1012: }
1013: return;
1014: }
1015: /******************************************************************************/
1016: int key_check (char *key) /* checks a global key in compressed form */
1017: {
1018: short ch,
1019: typ = 0;
1020:
1021: while ((ch = UNSIGN (*key++)) != g_EOL) {
1022: if (ch == (DEL << 1)) {
1023: if ((ch = UNSIGN (*key++)) == (DEL << 1))
1024: key++;
1025: ch = SP;
1026: }
1027: if (ch >= SP) {
1028: if (typ == 2)
1029: return 1;
1030: typ = 1;
1031: }
1032: /* alphabetics */
1033: else {
1034: if (typ == 1)
1035: return 1;
1036: typ = 2; /* numerics '.' '-' */
1037: if (ch >= 20 && ch != POINT && ch != MINUS)
1038: return 1; /* illegal character */
1039: }
1040: if (ch & 01)
1041: typ = 0; /* comma between two indices */
1042: }
1043: return 0;
1044: } /* end key_check */
1045: /******************************************************************************/
1.2 snw 1046: static short int g_collate (char s[], char t[]) /* if 't' follows 's' in MUMPS collating */
1.1 snw 1047: {
1048: register int chs = *s;
1049: register int cht = *t;
1050: register int tx = 0;
1051: register int sx;
1052: short dif;
1053:
1054: /* the empty one is the leader! */
1055: if (chs == g_EOL) {
1056: if (cht == g_EOL)
1057: return 2;
1058: return 1;
1059: }
1060: if (cht == g_EOL)
1061: return FALSE;
1062:
1063: while (cht == s[tx]) {
1064: if (cht == g_EOL)
1065: return 0;
1066: cht = t[++tx];
1067: } /* (s==t) */
1068: chs = s[tx];
1069: if (chs == OMEGA)
1070: return 0;
1071: if (chs == ALPHA)
1072: return cht != g_EOL;
1073: if (chs == g_EOL && t[tx - 1] & 01)
1074: return 1;
1075: if (cht == g_EOL && s[tx - 1] & 01)
1076: return 0;
1077:
1078: /* vade retro usque ad comma */
1079: if (tx > 0) {
1080: tx--;
1081: while ((t[tx] & 01) == 0)
1082: if (--tx < 0)
1083: break;
1084: tx++;
1085: }
1086: chs = s[tx];
1087: cht = t[tx];
1088: if (UNSIGN (chs) <= POINT) { /* then come numerics */
1089: if (UNSIGN (cht) > POINT)
1090: return UNSIGN (cht) != g_EOL;
1091: /* both are numeric! now compare numeric values */
1092: /*****g_comp()*********************************************************/
1093: if (chs == MINUS) {
1094: if (cht != MINUS)
1095: return 1;
1096: } else {
1097: if (cht == MINUS)
1098: return 0;
1099: }
1100: if (chs == 1 && cht == POINT)
1101: return 1;
1102: if (cht == 1 && chs == POINT)
1103: return 0;
1104: dif = sx = tx;
1105: while (s[sx] != POINT) {
1106: if (s[sx++] & 01)
1107: break;
1108: }
1109: while (t[tx] != POINT) {
1110: if (t[tx++] & 01)
1111: break;
1112: }
1113: if (tx > sx)
1114: return (cht != MINUS);
1115: if (tx < sx)
1116: return (cht == MINUS);
1117: tx = dif;
1118: while ((cht >> 1) == (chs >> 1)) {
1119: if (cht & 01)
1120: return t[dif] == MINUS;
1121: if (chs & 01)
1122: return t[dif] != MINUS;
1123: chs = s[++tx];
1124: cht = t[tx];
1125: }
1126: return (((cht >> 1) > (chs >> 1)) == (t[dif] != MINUS))
1127: && (t[tx] != s[tx]);
1128: /**********************************************************************/
1129: }
1130: if (UNSIGN (cht) <= POINT)
1131: return 0;
1132: while ((dif = (UNSIGN (cht) >> 1) - (UNSIGN (chs) >> 1)) == 0) { /* ASCII collating */
1133: if ((cht & 01) && ((chs & 01) == 0))
1134: return 0;
1135: if ((chs & 01) && ((cht & 01) == 0))
1136: return 1;
1137: chs = s[++tx];
1138: cht = t[tx];
1139: }
1140: if (chs == g_EOL)
1141: return 1;
1142: if (cht == g_EOL)
1143: return 0;
1144: return dif > 0;
1145: } /* end g_collate */
1146: /******************************************************************************/
1.2 snw 1147: void show (char key[])
1.1 snw 1148: {
1149: int k,
1150: ch,
1151: i,
1152: j;
1153: char data[256];
1154:
1155: k = 0;
1156: i = 0;
1157: j = 0;
1158: while ((ch = UNSIGN (key[i++])) != g_EOL) {
1159: if (k) {
1160: k = 0;
1161: if (ch > ' ')
1162: data[j++] = '"';
1163: }
1164: data[j] = (ch > SP ? (ch >> 1) : (ch < 20 ? (ch >> 1) + '0' : (ch >> 1) + ' '));
1165: if (data[j++] == '"')
1166: data[j++] = '"';
1167: if (ch & 01) {
1168: if (ch > SP)
1169: data[j++] = '"';
1170: data[j++] = ',';
1171: k = 1;
1172: }
1173: }
1174: data[j--] = 0;
1175: printf ("(%s);", data);
1176: return;
1177: } /* end show() */
1178: /******************************************************************************/
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>