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>