File:  [Coherent Logic Development] / freem / src / fma_globals.c
Revision 1.5: download - view: text, annotated - select for diffs
Sat Mar 22 18:43:54 2025 UTC (10 days, 5 hours ago) by snw
Branches: MAIN
CVS tags: v0-62-3, v0-62-2, HEAD
Make STRLEN 255 chars and add BIGSTR macro for larger buffers

/*
 *   $Id: fma_globals.c,v 1.5 2025/03/22 18:43:54 snw Exp $
 *    fmadm - globals
 *
 *  
 *   Author: Serena Willis <snw@coherent-logic.com>
 *    Copyright (C) 1998 MUG Deutschland
 *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
 *
 *
 *   This file is part of FreeM.
 *
 *   FreeM is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   FreeM is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero Public License for more details.
 *
 *   You should have received a copy of the GNU Affero Public License
 *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   $Log: fma_globals.c,v $
 *   Revision 1.5  2025/03/22 18:43:54  snw
 *   Make STRLEN 255 chars and add BIGSTR macro for larger buffers
 *
 *   Revision 1.4  2025/03/09 19:14:25  snw
 *   First phase of REUSE compliance and header reformat
 *
 *
 * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
 * SPDX-License-Identifier: AGPL-3.0-or-later 
 **/

#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "fmadm.h"

void gl (char *global, short kf, short df, short nr, int chop);
int gverify (char *gpath);
static short int g_collate ();			/* if 't' follows 's' in MUMPS collating */
int key_check (char *key);
void check (unsigned long blknbr);
static short int g_collate (char s[], char t[]);			/* if 't' follows 's' in MUMPS collating */
void show (char key[]);

/* global variables for gverify */
short   filedes;			/* file descriptor */
char    block[MAXLEV][BLOCKLEN];	/* block to be read */
char   *blck;				/* dto. as pointer */
unsigned long llink[MAXLEV];		/* left link pointers */
unsigned long rlink[MAXLEV];		/* right link pointers */
short   offsets[MAXLEV];		/* offsets */
short   type[MAXLEV];			/* block type */
extern short   level;				/* current level */
unsigned long no_of_blks;		/* number of blocks */
unsigned long freeblks;			/* free blocks list */
char    key[256];			/* current key in pointer block scan */
short   exstat = 0;			/* exit status */
void    showpath ();			/* display path of pointers */
/* end of global variables for gverify */


int fma_globals_list (int optc, char **opts)
{
    DIR *dir;
    struct dirent *ent;

    char filename[PATHLEN];

    int ct = 0;

    printf ("\nFreeM Global Listing\n");
    printf ("--------------------\n\n");

    printf ("Namespace:     %s\n", fma_namespace);
    printf ("Global Path:   %s\n\n", fma_global_path);

    if ((dir = opendir (fma_global_path)) == NULL) {
        fprintf (stderr, "fmadm:  could not open global directory %s\n", fma_global_path);
        return 1;
    }

    while ((ent = readdir (dir)) != NULL) {

        strncpy (filename, ent->d_name, PATHLEN - 1);

        if (filename[0] == '^' && filename[1] != '$') {
            printf (" %s\n", filename);        
            ct++;
        }
        
    }

    printf ("\n\n    - %d globals found\n\n", ct);
    closedir (dir);

    return 0;
}

int fma_globals_examine (int optc, char **opts)
{

    DIR *dir;
    struct dirent *ent;
    
    char gpath[PATHLEN];
    int i;
    int ct = 0;
    
    if ((dir = opendir (fma_global_path)) == NULL) {
        fprintf (stderr, "fmadm:  could not open global directory %s\n", fma_global_path);
        return 1;
    }
    
    printf ("\nFreeM Global Examine\n");
    printf ("--------------------\n\n");

    printf ("Namespace:         %s\n", fma_namespace);
    printf ("Global Path:       %s\n", fma_global_path);
    printf ("Globals Selected:  ");

    
    if (optc > 1) {
    
        for (i = fma_base_opt; i <= optc; i++) {
            printf ("%s ", opts[i]);
        }

        printf ("\n\n");
    
    }
    else {
        printf ("[ENTIRE NAMESPACE]\n\n");
    }


    if (optc > 1) {

        for (i = fma_base_opt; i < optc; i++) {

            snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);
            gl (gpath, FALSE, FALSE, FALSE, strlen (fma_global_path));

            ct++;

        }

    }
    else {

        while ((ent = readdir (dir)) != NULL) {

            strncpy (gpath, ent->d_name, PATHLEN - 1);
            
            if (gpath[0] == '^' && gpath[1] != '$') {

                snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, ent->d_name);

                gl (gpath, FALSE, FALSE, FALSE, strlen (fma_global_path));
                
                ct++;

            }

        }

    }

    printf ("\n\n");
    printf ("    - %d globals examined\n\n", ct);

    return 0;

}

int fma_globals_remove (int optc, char **opts)
{
    
    char gpath[PATHLEN];
    int i;
    int ct = 0;
    int er = 0;
    int tot = 0;

    printf ("\nFreeM Global Removal\n");
    printf ("--------------------\n\n");

    printf ("Namespace:     %s\n", fma_namespace);
    printf ("Global Path:   %s\n\n", fma_global_path);

    for (i = fma_base_opt; i < optc; i++) {
        printf ("%-10s\t", opts[i]);

        snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);

        if (unlink (gpath) == -1) {
            printf ("[FAIL]\n");
            er++;
        }
        else {
            printf ("[OK]\n");
            ct++;
        }

        tot++;
    
    }

    printf ("\nRemoved %d globals [%d errors/%d attempted]\n\n", ct, er, tot);

    return 0;

}

int fma_globals_verify (int optc, char **opts)
{
    DIR *dir;
    struct dirent *ent;
    
    char gpath[PATHLEN];
    int i;
    int ct = 0;

    if ((dir = opendir (fma_global_path)) == NULL) {
        fprintf (stderr, "fmadm:  could not open global directory %s\n", fma_global_path);
        return 1;
    }
                          
    printf ("\nFreeM Global Verify\n");
    printf ("-------------------\n\n");

    printf ("Namespace:         %s\n", fma_namespace);
    printf ("Global Path:       %s\n", fma_global_path);
    printf ("Globals Selected:  ");

    if (optc > fma_base_opt) {
    
        for (i = fma_base_opt; i < optc; i++) {
            printf ("%s ", opts[i]);
        }

        printf ("\n\n");
    
    }
    else {
        printf ("[ENTIRE NAMESPACE]\n\n");
    }


    if (optc > fma_base_opt) {

        for (i = fma_base_opt; i < optc; i++) {

            snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, opts[i]);

            exstat = 0;
            gverify (gpath);

            printf ("\n\t%d error(s) in %s\n", exstat, gpath);
            
            ct++;

        }

    }
    else {

        while ((ent = readdir (dir)) != NULL) {

            strncpy (gpath, ent->d_name, PATHLEN - 1);
            
            if (gpath[0] == '^') {

                snprintf (gpath, PATHLEN - 1, "%s/%s", fma_global_path, ent->d_name);

                exstat = 0;
                gverify (gpath);

                printf ("\n\t%d errors in %s\n", exstat, gpath);
                
                ct++;

            }

        }

    }

    printf ("\n\n");
    printf ("    - %d globals verified\n\n", ct);

    return 0;

}


/* PRIVATE FUNCTIONS */

/***
 * gl(): list global
 *
 *  global:  name of global
 *  kf:      key flag
 *  df:      data flag
 *  nr:      naked reference flag
 */
void gl (char *global, short kf, short df, short nr, int chop)
{
    short   filedes;            /* file descriptor */
    char    block[BLOCKLEN];    /* block to be read */
    char    key[512];
    char    prevkey[512];       /* previous key */
    char    data[1024];         /* if data has CTRLs it may become */
                                /* so long                         */
    unsigned long blknbr;
    short   offset;
    short   length;
    short   koffs;
    short   dkf = TRUE;
    
    short   CtrlFlag;
    short   n, k1;
    register int i, j, k, ch;
    
    if ((filedes = open (global, 0)) == -1) {
        printf ("%s: cannot open\012\015", global);
        
        return;
    }
    
    if (kf == FALSE && df == FALSE) {
        kf = TRUE;
        df = TRUE;
    } 
    else {
        dkf = FALSE;
    }
    
    blknbr = ROOT;
    prevkey[0] = 0;
    prevkey[1] = 0;
    prevkey[2] = 0;
    
    for (;;) {
        
        lseek (filedes, blknbr * BLOCKLEN, 0);
        
        if (read (filedes, block, BLOCKLEN) == 0) {
            fprintf (stderr, "\015*** something wrong ***\033[K\n\r");
            exit (0);
        }
        
        if (block[BTYP] == DATA) goto first;
        
        i = UNSIGN (block[0]) + 2;
        blknbr = UNSIGN (block[i]) * 65536 + UNSIGN (block[i + 1]) * 256 + UNSIGN (block[i + 2]);

    }

again:

    if (blknbr == 0) {
        close (filedes);
        return;
    }

    lseek (filedes, blknbr * 1024L, 0);
    read (filedes, block, BLOCKLEN);

first:

    offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
    blknbr = UNSIGN (block[RLPTR]) * 65536 + UNSIGN (block[RLPTR + 1]) * 256 + UNSIGN (block[RLPTR + 2]);

    i = 0;
    while (i < offset) {

        length = UNSIGN (block[i++]);
        k = koffs = UNSIGN (block[i++]);
        
        if ((i + length) > offset) break;

        for (j = 0; j < length; j++) key[k++] = block[i++];
        
        key[k] = g_EOL;
        {

            short   ch0, i, j, k;

            j = 0;
            i = 0;
            data[j++] = '(';
            k = 1;
            
            while ((ch = UNSIGN (key[i++])) != g_EOL) {
            
                if (k) {
                    k = 0;
                    if (ch > SP) data[j++] = '"';
                }

                ch0 = (ch >= SP ? (ch >> 1) :       /* 'string' chars */
                    (ch < 20 ? (ch >> 1) + '0' :    /* 0...9          */
                    (ch >> 1) + SP));               /* '.' or '-'     */
                
                if (ch0 == DEL) {
                    if ((ch0 = (UNSIGN (key[i++]) >> 1)) == DEL) {
                        ch0 = (UNSIGN (key[i++]) >> 1) + DEL;
                    }
                    
                    ch0 += DEL;
                    data[j] = '<';
                    data[++j] = '0' + ch0 / 100;
                    data[++j] = '0' + (ch0 % 100) / 10;
                    data[++j] = '0' + ch0 % 10;
                    data[++j] = '>';

                } 
                else {
                    data[j] = ch0;
                }

                if (data[j++] == '"') data[j++] = '"';

                if (ch & 01) {
                    
                    if (ch > SP) data[j++] = '"';
                    
                    data[j++] = ',';
                    k = 1;

                }

            }

            data[j--] = 0;
            data[j] = ')';
            
            if (j == 0) data[0] = 0;

            while (j >= 0) {
                if ((ch = data[--j]) < SP || ch >= DEL) break;
            }

            k1 = 0;
            if (nr) {

                if (prevkey[0]) {

                    n = ch = 0;

                    while (data[n] == prevkey[n]) {
                        
                        if (prevkey[n] == '"') ch = !ch;
                        if (!ch && k1 == 0 && (prevkey[n] == '(')) k1 = n + 1;
                        if (!ch && (prevkey[n] == ',')) k1 = n + 1;

                        n++;

                    }

                    while (prevkey[n]) {

                        if (prevkey[n] == '"') ch = !ch;
                        
                        if (!ch && (prevkey[n] == ',')) {
                            k1 = 0;
                            break;
                        }

                        n++;

                    }

                }

                strcpy (prevkey, data);

                if (k1 > 1) {
                    strcpy (&data[1], &data[k1]);
                }

            }

            if (j < 0) {

                if (kf) {
                    
                    if (k1) {
                        printf ("%c%s", '^', data);
                    } 
                    else {
                        printf ("%s%s", global + chop + 1, data);
                    }

                }

                if (dkf && !nr) {
                    printf ("=");
                }
                else if (kf) {
                    printf ("\n");
                }

            } 
            else {
                fprintf (stderr, "[%d][%d] <illegal subscript>\n", length, koffs);
            }

        }

        length = UNSIGN (block[i++]);
        
        stcpy0 (data, &block[i], (long) length);
        
        data[length] = EOL;
        
        if (numeric (data)) {
            data[length] = 0;
            i += length;
        } 
        else {

            CtrlFlag = 0;
            data[0] = '"';
            k = 1;

            while (length-- > 0) {
                
                ch = UNSIGN (block[i++]);
                
                if ((ch >= SP) && (ch < DEL)) {
                    
                    if (CtrlFlag) { /* close Bracket after CTRL */
                        
                        data[k++] = ')';
                        data[k++] = '_';
                        data[k++] = '"';

                        CtrlFlag = 0;

                    }

                    if ((data[k++] = ch) == '"') data[k++] = ch;

                } 
                else {
                    
                    if (((ch >= NUL) && (ch < SP)) || ch == DEL) {
                        
                        if (CtrlFlag) {
                            data[k++] = ',';
                        } 
                        else {

                            if (k > 1) {
                                data[k++] = '"';
                                data[k++] = '_';
                            } 
                            else {
                                k = 0;
                            }

                            data[k++] = '$';
                            data[k++] = 'C';
                            data[k++] = '(';

                            CtrlFlag = 1;

                        }
                        
                        if (ch == DEL) {
                            data[k++] = '1';
                            ch -= 100;
                        }

                        if (ch >= 10) {
                            data[k++] = ch / 10 + '0';
                            ch = ch % 10;
                        }

                        data[k++] = ch + '0';

                    } 
                    else {

                        if (CtrlFlag) { /* close Bracket after CTRL */

                            data[k++] = ')';
                            data[k++] = '_';
                            data[k++] = '"';

                            CtrlFlag = 0;

                        }

                        data[k++] = '<';

                        if (ch > 99) {
                            data[k++] = '0' + (ch / 100);
                            ch = ch % 100;
                        }

                        if (ch > 9) {
                            data[k++] = '0' + (ch / 10);
                            ch = ch % 10;
                        }

                        data[k++] = '0' + ch;
                        data[k++] = '>';

                    }
                }
            }

            if (CtrlFlag) {
                data[k++] = ')';
            }
            else {
                data[k++] = '"';
            }
            
            data[k] = 0;
        
        }

        if (df) printf ("%s\n", data);

    }

    if (i != offset) fprintf (stderr, "\nwrong offset %d vs. %d\n", offset, i);
    
    goto again;

}

int gverify (char *gpath)
{
    register int j;

    printf ("\n%s:\n\n", gpath);
    
    if ((filedes = open (gpath, 0)) == -1) {
	fprintf (stderr, "Cannot open file %s\007\n\r", gpath);
	return 1;
    }
    
    j = 0;

    while (j < MAXLEV) {

	rlink[j] = 0;
	llink[j] = 0;

        j++;
        
    }
    
    level = 0;

    check (ROOT);

    j = 1;				/* ignore level zero: there is no rightlink pointer (freeblocks instead) */
    while (j < MAXLEV) {		/* check last right link pointers (all zero!) */

	if (rlink[j] != 0) {
	    printf ("\tblock #%ld right link pointer mismatch 0 vs. %ld\012\015", llink[j], rlink[j]);
	    showpath ();
	}
        
	j++;
        
    }
    
   /* check free blocks */
    freeblks = UNSIGN (block[0][FREE]) * 65536 +
	    UNSIGN (block[0][FREE + 1]) * 256 +
	    UNSIGN (block[0][FREE + 2]);

    while (freeblks) {

        unsigned long free;
	int i;

	if (freeblks > no_of_blks) {
	    printf ("\tblock# %ld (free list) greater than number of blocks (%ld)\012\015", freeblks, no_of_blks);
	    showpath ();
	}

        lseek (filedes, (long) (freeblks) * BLOCKLEN, 0);

        if (read (filedes, block[0], BLOCKLEN) < BLOCKLEN) {

            printf ("\tblock #%ld is (partially) empty\012\015", freeblks);
	    showpath ();

            exit (exstat);

        }

        j = UNSIGN (block[0][OFFS]) * 256 +
		UNSIGN (block[0][OFFS + 1]);	/* offset */

        freeblks = UNSIGN (block[0][RLPTR]) * 65536 +
		UNSIGN (block[0][RLPTR + 1]) * 256 +
		UNSIGN (block[0][RLPTR + 1]);

        i = 0;

        while (i < j) {

            free = UNSIGN (block[0][i++]) * 65536;
	    free += UNSIGN (block[0][i++]) * 256;
	    free += UNSIGN (block[0][i++]);

            if (free > no_of_blks) {
		printf ("\tblock #%ld (free) greater than number of blocks (%ld)\012\015", free, no_of_blks);
		showpath ();
	    }

            lseek (filedes, free * BLOCKLEN, 0);
	    read (filedes, block[1], BLOCKLEN);

            if (block[1][BTYP] != EMPTY) {

                printf ("\tblock #%ld expected block type: EMPTY\012\015", free);

                if (++exstat >= ERRLIM) {
		    fprintf (stderr, "Error limit exceeded\012\015");
		    return exstat;
		}
                
	    }
            
	}

    }

    return exstat;

}

void check (unsigned long blknbr)
{
    unsigned long left;			/* current left link pointer */
    unsigned long right;		/* current right link pointer */
    long i;
    long k;

    lseek (filedes, blknbr * BLOCKLEN, 0);
    blck = block[level];
    
    if (read (filedes, blck, BLOCKLEN) < BLOCKLEN) {
	printf ("\tblock #%ld is (partially) empty\012\015", blknbr);
	showpath ();
    }

    type[level] = blck[BTYP];

    left = UNSIGN (blck[LLPTR]) * 65536 +
	    UNSIGN (blck[LLPTR + 1]) * 256 +
	    UNSIGN (blck[LLPTR + 2]);

    right = UNSIGN (blck[RLPTR]) * 65536 +
	    UNSIGN (blck[RLPTR + 1]) * 256 +
	    UNSIGN (blck[RLPTR + 2]);

    if (blknbr == ROOT) {
	no_of_blks = UNSIGN (block[0][NRBLK]) * 65536 +
            UNSIGN (block[0][NRBLK + 1]) * 256 +
            UNSIGN (block[0][NRBLK + 2]);
    }
    else {
        
	if (blknbr > no_of_blks) {
	    printf ("\tblock# %ld greater than number of blocks (%ld)\012\015", blknbr, no_of_blks);
	    showpath ();
	}
        
    }
    
    offsets[level] = UNSIGN (blck[OFFS]) * 256 + UNSIGN (blck[OFFS + 1]);
    
    if (rlink[level] != 0L && rlink[level] != blknbr) {
	printf ("\tblock #%ld right link pointer mismatch %ld vs. %ld\012\015", llink[level], blknbr, rlink[level]);
	showpath ();
    }
    
    if (llink[level] != 0L && left != llink[level]) {
	printf ("\tblock #%ld left link pointer mismatch %ld vs. %ld\012\015", blknbr, left, llink[level]);
	showpath ();
    }
    
    rlink[level] = right;
    llink[level] = blknbr;

    if (blknbr != ROOT) {

        k = UNSIGN (blck[0]);
	i = 0;

	while (i < k) {
	    if (blck[i + 2] != key[i]) {
		printf ("\tblock #%ld first key mismatch to pointer block(%ld)\012\015", blknbr, llink[level - 1]);
		showpath ();
		break;
	    }
	    i++;
	}
        
    }
    
    switch (type[level]) {
        
        case EMPTY:
            printf ("\tblock #%ld unexpected block type: EMPTY\012\015", blknbr);
            showpath ();
            break;

        case FBLK:
            printf ("\tblock #%ld unexpected block type: FBLK\012\015", blknbr);
            showpath ();
            break;

        case POINTER:
        case BOTTOM:
/*******************************/
/* scan pointer block */
	{
	    register long i;
	    register long k;
	    short j;
	    short len;
	    char key1[256];

	    key1[0] = g_EOL;
	    i = 0;
            
	    while (i < offsets[level]) {

                j = i++;		/* save adress of current entry */

                if ((len = UNSIGN (blck[j]) + (k = UNSIGN (blck[i++]))) > 255) {
		    printf ("\tblock #%ld key too long\012\015", blknbr);
		    showpath ();
		}
                else {

                    if (len == 0 && j) {
			printf ("\tblock #%ld empty key\012\015", blknbr);
			showpath ();
		    }

                    while (k < len) key[k++] = blck[i++];
                    
		    key[k] = g_EOL;

                    if (key_check (key)) {
			printf ("\tblock #%ld illegal key\012\015", blknbr);
			showpath ();
		    }
                    
		    if (g_collate (key1, key) == 0) {
			printf ("\tblock #%ld collation mismatch\012\015", blknbr);
			show (key1);
			show (key);
			showpath ();
		    }
                    
		    stcpy0 (key1, key, k + 1);
		    level++;

                    check ((long) (UNSIGN (blck[i]) * 65536 +
				   UNSIGN (blck[i + 1]) * 256 +
				   UNSIGN (blck[i + 2])));

                    blck = block[--level];

                }

                i += PLEN;

                if (i > DATALIM) {
		    printf ("\tblock #%ld pointer in status bytes\012\015", blknbr);
		    showpath ();
		}
                
	    }

            if (i > offsets[level]) {
		printf ("\tblock #%ld offset mismatch %ld vs. %d\012\015", blknbr, i, offsets[level]);
		showpath ();
	    }
	}
	break;
        
        case DATA:
             /* scan data block */
	{
	    register long i;
	    register long k;
	    short   len;
	    char    key0[256];
	    char    key1[256];

	    if (type[level - 1] != BOTTOM) {
		printf ("\tblock #%ld unexpected block type: DATA\012\015", blknbr);
		showpath ();
	    }

            key1[0] = g_EOL;
	    i = 0;

            while (i < offsets[level]) {

                len = UNSIGN (blck[i++]);
		len += (k = UNSIGN (blck[i++]));

                if (len > 255) {
		    printf ("\tblock #%ld key too long\012\015", blknbr);
		    showpath ();
		    i += len - k;
		}
                else {

                    if (len == 0 && i > 2) {
			printf ("\tblock #%ld empty key\012\015", blknbr);
			showpath ();
		    }
                    
		    while (k < len) key0[k++] = blck[i++];
                    
		    key0[k] = g_EOL;

                    if (key_check (key0)) {
			printf ("\tblock #%ld illegal key\012\015", blknbr);
			showpath ();
		    }
                    
		    if (g_collate (key1, key0) == 0) {
			printf ("\tblock #%ld collation mismatch\012\015", blknbr);
			show (key1);
			show (key0);
			showpath ();
		    }
                    
		    stcpy0 (key1, key0, k + 1);
		}
                
		k = i + 1;
		len = UNSIGN (blck[i]);
		i += UNSIGN (blck[i]);
		i++;			/* skip data */

#ifdef NEVER
		while (k < i) {
		    if (blck[k++] & ~0177) {
			printf ("\tblock #%ld illegal character in data string\012\015", blknbr);
			showpath ();
			break;
		    }
                }
#endif /* NEVER */
                
		if (i > DATALIM) {
		    printf ("\tblock #%ld data in status bytes\012\015", blknbr);
		    showpath ();
		}
                
	    }
            
	    if (i > offsets[level]) {
		printf ("\tblock #%ld offset mismatch %ld vs. %d\012\015", blknbr, i, offsets[level]);
		showpath ();
	    }
	}
	break;
        
        default:
            printf ("\tblock #%ld illegal type %d\012\015", blknbr, type[level]);
            showpath ();
            
    }
    
    return;
    
}					/* end check */
void
showpath ()
{					/* display path of pointers */
    int     i;

    if (level > 1)
	for (i = 0; i < level; i++)
	    printf ("  path level(%d)=%ld\012\015", i, llink[i]);
    if (++exstat >= ERRLIM) {
	fprintf (stderr, "Error limit exceeded (%hd errors)\012\015", exstat);
	return;
    }
    return;
}
/******************************************************************************/
int key_check (char *key)				/* checks a global key in compressed form */
{
    short   ch,
            typ = 0;

    while ((ch = UNSIGN (*key++)) != g_EOL) {
	if (ch == (DEL << 1)) {
	    if ((ch = UNSIGN (*key++)) == (DEL << 1))
		key++;
	    ch = SP;
	}
	if (ch >= SP) {
	    if (typ == 2)
		return 1;
	    typ = 1;
	}
/* alphabetics */
	else {
	    if (typ == 1)
		return 1;
	    typ = 2;			/* numerics '.' '-' */
	    if (ch >= 20 && ch != POINT && ch != MINUS)
		return 1;		/* illegal character */
	}
	if (ch & 01)
	    typ = 0;			/* comma between two indices */
    }
    return 0;
}					/* end key_check */
/******************************************************************************/
static short int g_collate (char s[], char t[])			/* if 't' follows 's' in MUMPS collating */
{
    register int chs = *s;
    register int cht = *t;
    register int tx = 0;
    register int sx;
    short   dif;

/* the empty one is the leader! */
    if (chs == g_EOL) {
	if (cht == g_EOL)
	    return 2;
	return 1;
    }
    if (cht == g_EOL)
	return FALSE;

    while (cht == s[tx]) {
	if (cht == g_EOL)
	    return 0;
	cht = t[++tx];
    }					/* (s==t) */
    chs = s[tx];
    if (chs == OMEGA)
	return 0;
    if (chs == ALPHA)
	return cht != g_EOL;
    if (chs == g_EOL && t[tx - 1] & 01)
	return 1;
    if (cht == g_EOL && s[tx - 1] & 01)
	return 0;

/* vade retro usque ad comma */
    if (tx > 0) {
	tx--;
	while ((t[tx] & 01) == 0)
	    if (--tx < 0)
		break;
	tx++;
    }
    chs = s[tx];
    cht = t[tx];
    if (UNSIGN (chs) <= POINT) {	/* then come numerics */
	if (UNSIGN (cht) > POINT)
	    return UNSIGN (cht) != g_EOL;
/* both are numeric! now compare numeric values */
/*****g_comp()*********************************************************/
	if (chs == MINUS) {
	    if (cht != MINUS)
		return 1;
	} else {
	    if (cht == MINUS)
		return 0;
	}
	if (chs == 1 && cht == POINT)
	    return 1;
	if (cht == 1 && chs == POINT)
	    return 0;
	dif = sx = tx;
	while (s[sx] != POINT) {
	    if (s[sx++] & 01)
		break;
	}
	while (t[tx] != POINT) {
	    if (t[tx++] & 01)
		break;
	}
	if (tx > sx)
	    return (cht != MINUS);
	if (tx < sx)
	    return (cht == MINUS);
	tx = dif;
	while ((cht >> 1) == (chs >> 1)) {
	    if (cht & 01)
		return t[dif] == MINUS;
	    if (chs & 01)
		return t[dif] != MINUS;
	    chs = s[++tx];
	    cht = t[tx];
	}
	return (((cht >> 1) > (chs >> 1)) == (t[dif] != MINUS))
		&& (t[tx] != s[tx]);
/**********************************************************************/
    }
    if (UNSIGN (cht) <= POINT)
	return 0;
    while ((dif = (UNSIGN (cht) >> 1) - (UNSIGN (chs) >> 1)) == 0) {	/* ASCII collating */
	if ((cht & 01) && ((chs & 01) == 0))
	    return 0;
	if ((chs & 01) && ((cht & 01) == 0))
	    return 1;
	chs = s[++tx];
	cht = t[tx];
    }
    if (chs == g_EOL)
	return 1;
    if (cht == g_EOL)
	return 0;
    return dif > 0;
}					/* end g_collate */
/******************************************************************************/
void show (char key[])
{
    int     k,
            ch,
            i,
            j;
    char    data[256];

    k = 0;
    i = 0;
    j = 0;
    while ((ch = UNSIGN (key[i++])) != g_EOL) {
	if (k) {
	    k = 0;
	    if (ch > ' ')
		data[j++] = '"';
	}
	data[j] = (ch > SP ? (ch >> 1) : (ch < 20 ? (ch >> 1) + '0' : (ch >> 1) + ' '));
	if (data[j++] == '"')
	    data[j++] = '"';
	if (ch & 01) {
	    if (ch > SP)
		data[j++] = '"';
	    data[j++] = ',';
	    k = 1;
	}
    }
    data[j--] = 0;
    printf ("(%s);", data);
    return;
}					/* end show() */
/******************************************************************************/

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>