File:  [Coherent Logic Development] / freem / src / fma_globals.c
Revision 1.6: download - view: text, annotated - select for diffs
Fri May 2 16:30:16 2025 UTC (3 months ago) by snw
Branches: MAIN
CVS tags: HEAD
Fix broken build due to time issues

    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>