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