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