File:  [Coherent Logic Development] / freem / src / symtab_bltin.c
Revision 1.7: download - view: text, annotated - select for diffs
Wed Mar 26 15:17:12 2025 UTC (6 days, 9 hours ago) by snw
Branches: MAIN
CVS tags: v0-62-3, HEAD
Fall back to global-backed SSVNs when memory-backed globals fail in attempt to fix Tru64

/*
 *   $Id: symtab_bltin.c,v 1.7 2025/03/26 15:17:12 snw Exp $
 *      FreeM local system table and user-defined special variable table 
 *
 *  
 *   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: symtab_bltin.c,v $
 *   Revision 1.7  2025/03/26 15:17:12  snw
 *   Fall back to global-backed SSVNs when memory-backed globals fail in attempt to fix Tru64
 *
 *   Revision 1.6  2025/03/24 04:13:11  snw
 *   Replace action macro dat with fra_dat to avoid symbol conflict on OS/2
 *
 *   Revision 1.5  2025/03/24 02:01:41  snw
 *   Work around some OS/2 incompatibilities in symbol table code
 *
 *   Revision 1.4  2025/03/09 19:50:47  snw
 *   Second 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>
#define ZNEW        'N'
#include "mpsdef.h"
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include "mdebug.h"
#include "merr.h"
#include "consttbl.h"
#include "shmmgr.h"

/* Turn this on to get tons of lovely debugging messages about
symbol-table calls */
/* #define DEBUG_SYM  */

short st_use_shm = FALSE;
short restoring_consts = FALSE;
int semid_symtab;

#if !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(__OS2__)
union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                (Linux-specific) */
};
#endif


long str2long(char *string) 
{
    int loop = 0; 
    int mult = 1;
    int exp = 1;
    long value = 0;
    
    if (string[0] == '-') { 
        mult = -1; 
        string++; 
    }
    
    while(string[loop] != EOL && string[loop] >= '0' && string[loop] <= '9') loop++;
    
    loop--;
    
    while(loop > -1) {
        value += (string[loop] - '0') * exp;
        exp *= 10; loop--;
    }

    value *= mult;
    
    return value;
}

void symtab_init (void)
{
    register int i;
    union semun arg;
    key_t symtab_sk;
    symtab_sk = ftok (config_file, 6);

    
    if (first_process) {
        
        for (i = 0; i < 128; i++) {
            shm_config->hdr->alphptr[i] = 0L;
        }

        shm_config->hdr->symlen = PSIZE;
        shm_config->hdr->s = &mbpartition[PSIZE] - 256;
        shm_config->hdr->PSIZE = DEFPSIZE;
        shm_config->hdr->argptr = mbpartition;
        
        fprintf (stderr, "symtab_init:  initializing memory-backed globals\r\n");        

        semid_symtab = semget (symtab_sk, 1, 0666 | IPC_CREAT);
        if (semid_symtab == -1) {
            fprintf (stderr, "symtab_init:  failed to create symbol table semaphore\r\n");
            exit (1);
        }
        else {
            fprintf (stderr, "symtab_init:  symbol table semaphore created with semid %d\r\n", semid_symtab);
        }

        arg.val = 1;
        if (semctl (semid_symtab, 0, SETVAL, arg) == -1) {
            fprintf (stderr, "symtab_init:  failed to initialize symbol table semaphore\r\n");
            exit (1);
        }
        else {
            fprintf (stderr, "symtab_init:  symbol table semaphore initialized\r\n");
        }

        fprintf (stderr, "symtab_init:  allocating partition for memory-backed globals\r\n");
        
        mbpartition = (char *) shm_alloc ((size_t) PSIZE + 2);
        if (mbpartition != NULL) {
            shm_config->hdr->use_mb_globals = TRUE;
        }
        else {
            fprintf (stderr, "symtab_init:  falling back to global-backed structured system variables\r\n");
            shm_config->hdr->use_mb_globals = FALSE;
        }

        shm_config->hdr->partition = mbpartition;
        
        if (symtab_get_sem ()) {
            for (i = 0; i < 128; i++) shm_config->hdr->alphptr[i] = 0L;
            symtab_release_sem ();
        }
        
    }
    else {

        semid_symtab = semget (symtab_sk, 1, 0);
        if (semid_symtab == -1) {
            fprintf (stderr, "symtab_init:  could not attach to symbol table semaphore\r\n");
            exit (1);
        }
        
        mbpartition = shm_config->hdr->partition;

    }
   
}

short have_symtab_sem = FALSE;

short symtab_get_sem(void)
{
    int tries;
    struct sembuf s = {0, -1, IPC_NOWAIT};

    if (have_symtab_sem) {
        return TRUE;
    }
    
    for (tries = 0; tries < 5; tries++) {

        if (semop (semid_symtab, &s, 1) != -1) {
            have_symtab_sem = TRUE;           
            return TRUE;
        }

        sleep (1);

    }
    fprintf (stderr, "symtab_get_sem:  fail\r\n");
    
    have_symtab_sem = FALSE;
    return FALSE;
}

void symtab_release_sem(void)
{
    struct sembuf s = {0, 1, 0};

    semop (semid_symtab, &s, 1);

    have_symtab_sem = FALSE;
}


void symtab_shm (short action, char *key, char *data)		/* symbol table functions */
{
    char *old_s;
    char *old_argptr;
    long old_psize;
    long old_symlen;
    unsigned long stptrs[128];
    register int i;
    char *old_partition = partition;

    if (shm_config->hdr->use_mb_globals == FALSE) {
        symtab_bltin (action, key, data);
        return;
    }
    partition = mbpartition;

    writing_mb = TRUE;

    if (symtab_get_sem ()) {

        /* save off current non-shared symtab state */
        old_s = s;
        old_argptr = argptr;
        old_psize = PSIZE;
        old_symlen = symlen;
        for (i = 0; i < 128; i++) {
            stptrs[i] = alphptr[i];
        }

        /* replace symtab state with the values from the shared symtab */
        s = shm_config->hdr->s;
        argptr = shm_config->hdr->argptr;
        PSIZE = shm_config->hdr->PSIZE;
        symlen = shm_config->hdr->symlen;       
        for (i = 0; i < 128; i++) {
            alphptr[i] = shm_config->hdr->alphptr[i];
        }

        /* execute the action (symtab_bltin will now be working with the shared symbol table) */
        symtab_bltin (action, key, data);

        /* copy new alphptr state back to shared memory */
        for (i = 0; i < 128; i++) {
            shm_config->hdr->alphptr[i] = alphptr[i];
        }

        /* restore non-shared symtab alphptr state */
        for (i = 0; i < 128; i++) {
            alphptr[i] = stptrs[i];
        }

        /* write the new shared symtab state back to shared memory */
        shm_config->hdr->s = s;
        shm_config->hdr->argptr = argptr;
        shm_config->hdr->PSIZE = PSIZE;
        shm_config->hdr->symlen = symlen;

        /* restore the non-shared symtab state */
        s = old_s;
        argptr = old_argptr;
        PSIZE = old_psize;
        symlen = old_symlen;        
        
        symtab_release_sem ();
        
    }
    else {
        fprintf (stderr, "symtab_shm:  failed to acquire symbol table sempahore\r\n");
    }

    writing_mb = FALSE;
    partition = old_partition;        
    
}

/* local symbol table management */
/* (+)functions are now re-implemented */
/* (!)functions are new */
/* (?)re-implemented, with issues */
/* +set_sym      +get_sym   */

/* +kill_sym     +$data     */
/* +kill_all     +$fra_order    */
/* +killexcl     +fra_query     */
/* +new_sym      +bigquery  */
/* +new_all      +getinc    */
/* +newexcl                 */
/* +killone      +m_alias   */
/* !merge_sym    +zdata     */
/* !pop_sym       */



/* The symbol table is placed at the high end of 'partition'. It begins at
* 'symlen' and ends at 'PSIZE'. The layout is
* (keylength)(key...)(<EOL>)(datalength)(data...[<EOL>])
* The keys are sorted in $order sequence.
* 
* ****possible future layout with less space requirements****
* (keylength)(statusbyte)(key...)[(datalength)(data...[<EOL>])]
* 'keylength' is the length of 'key' overhead bytes not included.
* 'statusbyte' is an indicator with the following bits:
* 0  (LSB)        1=data information is missing 0=there is a data field
* 1               1=key is numeric              0=key is alphabetic
* 2..7            0..number of previous key_pieces
* note, that the status byte of a defined unsubscripted variable
* is zero.
* If a subscripted variable is stored, the variablename and each
* subscript are separate entries in the symbol table.
* E.g. S USA("CA",6789)="California" ; with $D(ABC)=0 before the set
* then the following format is used:
* (3)(    1)ABC
* (2)(1*4+1)CA
* (4)(2*4+2)6789(10)California
* ****end of "possible future layout"****
* To have the same fast access regardless of the position in the
* alphabet for each character a pointer to the first variable beginning
* with that letter is maintained. (0 indicates there's no such var.)
*/

void symtab_bltin (short action, char *key, char *data)		/* symbol table functions */
{
    /* must be static:                */
    static unsigned long tryfast = 0L;	/* last $order reference          */

    /* the following variables may    */
    /* be static or not               */
    static unsigned short nocompact = TRUE;	/* flag: do not compact symtab if */

    /* value becomes shorter          */
    /* be static or dynamic:          */

    static long keyl, datal;			/* length of key and data                 */
    static long kill_from;
    static char tmp1[256], tmp2[256], tmp3[256];

    register long i, j, k, k1;
    char tt_with[STRLEN];
    char tt_key[STRLEN];

#ifdef DEBUG_SYM

    int i0, i1;
    char *start;

#endif

    if (restoring_consts == FALSE) {
        if (((action % 2) == 0) && const_is_defined (key)) {
            merr_raise (CMODIFY);
            return;
        }
    }
    
    if (action == kill_all) goto no_with;
    if ((stlen (key) >= 5) && (strncmp (key, "%INT.", 5) == 0)) goto no_with;
    if (strncmp (key, "^$", 2) == 0) goto no_with;
    if (strncmp (key, "$", 1) == 0) goto no_with;
    
    stcpy (tt_with, i_with);
    stcpy (tt_key, key);
    
    stcnv_m2c (tt_with);
    stcnv_m2c (tt_key);
    
    snprintf (key, 100, "%s%s\201\201", tt_with, tt_key);

    
no_with:    
    
    
    if (dbg_enable_watch && ((action % 2) == 0)) dbg_fire_watch (key);

    if (key && key[1] != '$') stcpy (zloc, key);   
    
    if (v22ptr) {

        procv22 (key);
        
        if (key[0] == '^') {
            
            char    zrsav[256];
            int     naksav;
            char    gosav[256];

            stcpy (zrsav, zref);
        
            naksav = nakoffs;
        
            stcpy (gosav, g_o_val);
            global  (action, key, data);

            stcpy (zref, zrsav);
            
            nakoffs = naksav;
            
            stcpy (l_o_val, g_o_val);
            stcpy (g_o_val, gosav);
            
            return;

        }

    }

    /* process optional limitations */
    if (glvnflag.all && key[0] >= '%' && key[0] <= 'z') {
        
        if ((i = glvnflag.one[0])) {	/* number of significant chars */
            
            j = 0;
        
            while ((k1 = key[j]) != DELIM && k1 != EOL) {
                
                if (j >= i) {
       
                    while ((k1 = key[++j]) != DELIM && k1 != EOL) ;
        
                    stcpy (&key[i], &key[j]);
        
                    break;
        
                }
                
                j++;
            }
        
        }
        
        if (glvnflag.one[1]) {		/* upper/lower sensitivity */
        
            j = 0;
        
            while ((k1 = key[j]) != DELIM && k1 != EOL) {
                
                if (k1 >= 'a' && k1 <= 'z') key[j] = k1 - 32;
            
                j++;

            }

        }

        
        if ((i = glvnflag.one[2])) {

            /* IMPACT: x11-94-28 */
            if (stlen (key) > i) {
                merr_raise (M75);
                return;
            }				/* key length limit */

        }

        if ((i = glvnflag.one[3])) {	/* subscript length limit */
            
            j = 0;
            
            while ((k1 = key[j++]) != DELIM && k1 != EOL) ;
            
            if (k1 == DELIM) {

                k = 0;

                for (;;) {

                    k1 = key[j++];
                    
                    if (k1 == DELIM || k1 == EOL) {
                        
                        if (k > i) {
                            merr_raise (M75);
                            return;
                        }
                    
                        k = 0;
                    
                    }
                    
                    if (k1 == EOL) break;
                    
                    k++;
                
                }
            }
        }
    }


    
    if (aliases && (action != m_alias)) {	/* there are aliases */
    
        i = 0;
        j = 0;
    
        while (i < aliases) {

            k1 = i + UNSIGN (ali[i]) + 1;
            
            /* is current reference an alias ??? */
            j = 0;
            
            while (ali[++i] == key[j]) {

                if (ali[i] == EOL) break;
            
                j++;

            }

            /* yes, it is, so resolve it now! */
            if (ali[i] == EOL && (key[j] == EOL || key[j] == DELIM)) {
                
                stcpy (tmp1, key);
                stcpy (key, &ali[i + 1]);
                stcat (key, &tmp1[j]);
                
                i = 0;
                
                continue;		/* try again, it might be a double alias! */

            }

            i = k1;

        }

    }

#ifdef DEBUG_SYM 
    
    printf("DEBUG (%d): ",action);

    if(key) {
    
        printf("[key] is [");
    
        for(loop=0; key[loop] != EOL; loop++) printf("%c",(key[loop] == DELIM) ? '!' : key[loop]);

        printf("]\r\n");

    } 
    else {  
        printf("No key passed in.\r\n");
    }

    if(data) {
        
        printf("[data] (datalen) is [");
    
        for(loop=0; data[loop] != EOL; loop++) printf("%c", data[loop]);
    
        printf("] (%d)\r\n",stlen(data));
        printf("[Numeric?] is [%d]\r\n",is_numeric(data));

    } 
    else { 
        printf("No data passed in.\r\n");
    }

#endif 

    switch (action) {

        
        case get_sym:			/* retrieve */
            

            /* OLD get_sym routine */     
            if ((i = alphptr[(int) key[0]])) {

//                printf ("alphptr match; writing_mb = %d\r\n", writing_mb);                
                
                k = 1;
                j = i + 1;			/* first char always matches! */
                
                do {
                    
                    while (key[k] == partition[++j]) {	/* compare keys */

                        if (key[k] == EOL) {

                            /* IMPACT: x11-94-28  */
                            i = UNSIGN (partition[++j]);
                            
                            if (i < 4) {
                            
                                k = 0;
                            
                                while (k < i) data[k++] = partition[++j];

                            } 
                            else {
                                stcpy0 (data, &partition[j + 1], i);
                            }
                            
                            data[i] = EOL;
                            
                            return;
                        
                        }
                        
                        k++;

                    }

                    i += UNSIGN (partition[i]);	/* skip key */
                    i += UNSIGN (partition[i]) + 1;		/* skip data */

                    k = 0;
                    j = i;
                
                } while (i < PSIZE);
            }

            merr_raise (M6);
            data[0] = EOL;
            
            return;





        case set_sym:			/* store/create variable */


            /* HANDLE ISVs FROM unnew() */

            if (key[0] == '$') {

                switch (key[1]) {

                    case 't':               /* $TEST */

                        test = data[0];
                        break;

                    case 'z':               /* $Z ISVs */

                        if (key[2] == 'r') {  /* $ZREFERENCE / $REFERENCE */
                            stcpy (zref, data);
                        }

                        break;

                }

            }

            datal = stlen (data);		/* data length */





            /* Old set_sym routine */
            /* check whether the key has subscripts or not */
            if ((keyl = stlen (key) + 2) > STRLEN) { 
                merr_raise (M75); 
                return; 
            }
            
            k1 = 0;
            i = 1;
            
            while (key[i] != EOL) {

                if (key[i++] == DELIM) {
                    k1 = i;
                    break;
                }

            }

            if ((i = alphptr[(int) key[0]])) {	/* previous entry */
                
                j = i + 1;
                k = 1;

            } 
            else {
                
                i = symlen;
                j = i;
                k = 0;

            }

            if (k1 == 0)			/* key was unsubscripted */

                /* compare keys */            
                while (i < PSIZE) {
                    
                    while (key[k] == partition[++j]) {
                    
                        if (key[k] == EOL) goto old;
                    
                        k++;
                    
                    }
                    
                    if (key[k] < partition[j]) break;
                    
                    i += UNSIGN (partition[i]);	/* skip key */
                    i += UNSIGN (partition[i]) + 1;		/* skip data */
                    
                    j = i;
                    k = 0;

                } 
                else {				/* key was subscripted */
            
                    /* compare keys */
                    while (i < PSIZE) {
                        
                        while (key[k] == partition[++j]) {
                            
                            if (key[k] == EOL) goto old;
                            
                            k++;

                        }

                        
                        if (k < k1) {
                            if (key[k] < partition[j]) break;
                        } 
                        else {
                            
                            long    m, n, o, ch;

                            /* get complete subscripts */
                            n = k;
                            
                            while (key[--n] != DELIM) ;
                            
                            n++;
                            m = j + n - k;
                            o = 0;
                            
                            while ((ch = tmp3[o++] = partition[m++]) != EOL && ch != DELIM) ;
                            
                            if (ch == DELIM) tmp3[--o] = EOL;
                            
                            o = 0;
                            
                            while ((ch = tmp2[o++] = key[n++]) != EOL && ch != DELIM) ;
                            
                            if (ch == DELIM) tmp2[--o] = EOL;

                            if (collate (tmp3, tmp2) == FALSE) {
                                if (stcmp (tmp2, tmp3) || ch == EOL) break;
                            }

                        }
                    
                        i += UNSIGN (partition[i]);	/* skip key */
                        i += UNSIGN (partition[i]) + 1;		/* skip data */
                        
                        j = i;
                        k = 0;

                    }
                }

                /* if    entry found,     i pointer to searched entry
                * else  entry not found, i pointer to alphabetically next entry */
                
                /* new entry */
                if (setop) {

                    tmp1[0] = EOL;
                    
                    m_op (tmp1, data, setop);
                    
                    setop = 0;
                    
                    if (merr () > OK) return;

                    datal = stcpy (data, tmp1);
                
                }
                
                k = i;
                j = key[0];
                i = keyl + datal + 1;
                
                if (alphptr['%']) alphptr['%'] -= i;

                for (k1 = 'A'; k1 <= j; k1++) {
                    if (alphptr[k1]) alphptr[k1] -= i;
                }

                i = k - i;
                
                if (alphptr[j] == 0 || alphptr[j] > i) alphptr[j] = i;

                j = keyl + datal + 1;
                i = symlen - j;
                
                if (i <= 256) {			/* more space needed. try to get it */
                    
                    long    dif = 0L;

                    dif = getpmore ();
                    
                    if (dif == 0) {
                        merr_raise (STORE);
                        return;
                    }

                    data = argptr;
                    i += dif;
                    k += dif;

                }

                symlen = i;
                s = &partition[i] - 256;
                
                stcpy0 (&partition[i], &partition[j + i], k - i);
                
                i = k - (keyl + datal + 1);
                partition[i++] = (char) (keyl);
                
                stcpy (&partition[i], key);	/* store new key */
                
                i += keyl - 1;

                /* IMPACT: x11-94-28 */
                partition[i++] = (char) (datal);
                
                stcpy0 (&partition[i], data, datal);	/* store new data */
                
                return;

                /* there is a previous value */
old:
                i += UNSIGN (partition[i]);
                
                if (setop) {

                    j = UNSIGN (partition[i]);
                    stcpy0 (tmp1, &partition[i + 1], j);
                    
                    tmp1[j] = EOL;
                    
                    m_op (tmp1, data, setop);
                    
                    setop = 0;
                    
                    if (merr () > OK) return;

                    datal = stcpy (data, tmp1);
                
                }

old0:				/* entry from getinc */

                /* IMPACT: x11-94-28 */
                j = UNSIGN (partition[i]) - datal;
                
                if (j < 0) {			/* more space needed */

                    if ((symlen + j) <= 256) {
                     
                        long    dif = 0L;

                        dif = getpmore ();
                    
                        if (dif == 0L) {
                            merr_raise (STORE);
                            return;
                        }

                        data = argptr;
                        i += dif;
    
                    }
    
                    for (k = 36; k < key[0]; k++) {
                        if (alphptr[k])
                        alphptr[k] += j;
                    }

                    if (alphptr[k] && alphptr[k] < i) alphptr[k] += j;

                    stcpy0 (&partition[symlen + j], &partition[symlen], i - symlen);
                    
                    i += j;
                    symlen += j;
                    s = &partition[symlen] - 256;
                    tryfast = 0;

                } 
                else if (j > 0) {		/* surplus space */
                                        
                    if (nocompact) {
                        
                        /* in a dynamic environment it is sufficient to          */
                        /* set newdatalength=olddatalength                       */ 
                        
                        datal += j;

                    }
                    else {
                
                        /* instead of compression of the local symbol table,     */
                        /* which the following piece of code does                */
                        
                        symlen += j;
                        s = &partition[symlen] - 256;
                        
                        for (k = 36; k < key[0]; k++) {
                            if (alphptr[k]) alphptr[k] += j;
                        }

                        if (alphptr[k] && alphptr[k] < i) alphptr[k] += j;
                        
                        i += j;
                        k = i;
                        j = i - j;
                        
                        while (i >= symlen) {
                            partition[i--] = partition[j--];
                        }

                        i = k;
                        tryfast = 0;
                        nocompact = TRUE;
                    
                    }
                }

                /* IMPACT: x11-94-28 */
                partition[i++] = (char) (datal);
                j = datal;
                
                if (j < 4) {
                    
                    k = 0;
                    
                    while (k < j) partition[i++] = data[k++];
                    
                    return;

                }

                stcpy0 (&partition[i], data, j);	/* store new data */

                return;

            /* end of set_sym section */

            
            case fra_dat:


                /* note: we assume EOL<DELIM<ASCII */
                data[0] = '0';
                data[1] = EOL;
                
                if ((i = alphptr[(int) key[0]])) {

                    data[2] = EOL;
                    j = i + 1;
                    k = 1;
                    
                    do {

                        while ((k1 = key[k] - partition[++j]) == 0) {	/* compare keys */
                            
                            if (key[k] == EOL) break;
                            
                            k++;

                        }

                        if (k1 == 0) {
                            data[0] = '1';
                        }
                        else {
                            
                            if (partition[j] == DELIM && key[k] == EOL) {
                            
                                data[1] = data[0];
                                data[0] = '1';
                            
                                return;
                            
                            }
                            
                            if (k1 < 0 && k < 2) return;

                        }
                        
                        i += UNSIGN (partition[i]);	/* skip key */
                        i += UNSIGN (partition[i]) + 1;		/* skip data */
                        
                        j = i;
                        k = 0;

                    } while (i < PSIZE);

                }

                return;



            /* end of $data section */


 

            case getinc:			/* increment by one and retrieve */

#ifdef DEBUG_SYM
                
                printf ("DEBUG GETINC: ");
                printf ("[key] is [");

                for (loop = 0; key[loop] != EOL; loop++) printf ("%c", (key[loop] == DELIM) ? '!' : key[loop]);

                printf("]\r\n");
#endif


                if ((i = alphptr[(int) key[0]])) {

                    j = i + 1;
                    k = 1;
                    
                    do {
                        
                        while (key[k] == partition[++j]) {	/* compare keys */
                    
                            if (key[k] == EOL) {

                                i = UNSIGN (partition[++j]);
                                stcpy0 (data, &partition[j + 1], i);
                                
                                data[i] = EOL;	/* data retrieved ... now increment */
                                
                                /****************increment by one*******************/
                                if (i == 0) i++;	/* if data was empty  use EOL as dummy value */
                                if (i > 1 && data[0] == '0') i++;	/* leading zero  use EOL as dummy value */
                                
                                k = 0;
                                
                                while (k < i) {

                                    if ((k1 = data[k++]) < '0' || k1 > '9') {	/* no positive integer */
                                        
                                        numlit (data);
                                        
                                        tmp1[0] = '1';
                                        tmp1[1] = EOL;
                                        
                                        add (data, tmp1);
                                        
                                        datal = stlen (data);
                                        
                                        i = j;
                                        
                                        nocompact = FALSE;	/* getinc needs compacted symtab */
                                        
                                        goto old0; 

                                    }

                                }

                                k1 = k--;	/* length of string */
                                
                                while ((partition[j + 1 + k] = ++data[k]) > '9') {

                                    partition[j + 1 + k] = '0';
                                    data[k--] = '0';
                                    
                                    if (k < 0) {

                                        k = k1;
                                        
                                        while (k >= 0) {
                                            data[k + 1] = data[k];
                                            k--;
                                        }

                                        data[0] = '1';
                                        s = &partition[--symlen] - 256;
                                        
                                        if (alphptr['%']) alphptr['%']--;

                                        for (k = 'A'; k <= key[0]; k++) {
                                            if (alphptr[k]) alphptr[k]--;
                                        }

                                        k = j - 1;
                                        j = symlen;
                                        
                                        stcpy0 (&partition[j], &partition[j + 1], k - j);
                                        
                                        partition[k] = (char) ++i;
                                        partition[++k] = '1';
                                        
                                        return;

                                    }

                                }

                                return;
                                
                                /************end increment by one*******************/
                            
                            }
                    
                            k++;

                        }

                        /** if (key[k]<partition[j]) break; **/
                        i += UNSIGN (partition[i]);	/* skip key */
                        i += UNSIGN (partition[i]) + 1;		/* skip data */

                        j = i;
                        k = 0;
                        
                    } while (i < PSIZE);
                
                }
                
                data[0] = EOL;
                merr_raise (UNDEF);
                
                return;



            case fra_order:			/* next one please */


                if (ordercnt < 0) goto zinv;

                k1 = (j = stcpy (tmp1, key) - 1);
                
                while (tmp1[k1] != DELIM) {
                    if ((--k1) <= 0) goto unsubscr;
                }

                tmp1[++k1] = EOL;
                
                stcpy (tmp2, &key[k1]);
                
                if (ordercnt == 0) {
                
                    stcpy (data, tmp2);

                    l_o_val[0] = EOL;
                    
                    return;

                }

                data[0] = EOL;
                
                if ((i = alphptr[(int) key[0]]) == 0) {

                    l_o_val[0] = EOL;

                    
                    return;

                }

                /***************************/
                /* frequent special case: the key of which we search the next
                * entry is defined ! */
                if (tmp2[0] != EOL) {

                    if (tryfast && stcmp (key, &partition[tryfast + 1]) == 0) {
                        
                        j = tryfast;
                        j += UNSIGN (partition[j]);	/* skip key */
                        j += UNSIGN (partition[j]) + 1;		/* skip data */
                        
                        goto begorder;

                    }

                    k = 1;
                    j = i + 1;			/* first char always matches! */
                    
                    do {

                        while (key[k] == partition[++j]) {	/* compare keys */

                            if (key[k++] == EOL) {
                                j = i;
                                goto begorder;
                            }
                        
                        }
                        
                        i += UNSIGN (partition[i]);	/* skip key */
                        i += UNSIGN (partition[i]) + 1;		/* skip data */
                        
                        k = 0;
                        j = i;

                    } while (i < PSIZE);

                }

                /* the key was not defined */
                /***************************/
                j = alphptr[(int) key[0]];

begorder:

                do {
                    
                    if (key[0] != partition[j + 1]) {
                    
                        l_o_val[0] = EOL;
                        data[0] = EOL;
                        
                        return;
                    
                    }

                    stcpy0 (data, &partition[j + 1], k1);
                    
                    data[k1] = EOL;

                    if (stcmp (tmp1, data) == 0) {
                        
                        stcpy (data, &partition[j + 1 + k1]);	/* index on same level */
                        
                        k = 0;
                        
                        while (data[k] != EOL && data[k] != DELIM) k++;

                        data[k] = EOL;
                        
                        if (collate (tmp2, data)) {

                            if (--ordercnt <= 0) {

                                tryfast = j;
                                
                                /* save data value for inspection with $V(110) */
                                j += UNSIGN (partition[j]);	/* skip key */
                                k = UNSIGN (partition[j++]);
                                stcpy0 (l_o_val, &partition[j], k);
                                
                                l_o_val[k] = EOL;
                                
                                return;

                            }

                            ordercounter++;

                        }

                    }
                    
                    j += UNSIGN (partition[j]);	/* skip key */
                    j += UNSIGN (partition[j]) + 1;	/* skip data */

                } while (j < PSIZE);

                data[0] = EOL;
                tryfast = 0;
                l_o_val[0] = EOL;
                
                return;

            /* end of $order section */


        case kill_all:

genocid:




            /* Old genocide routine */
            alphptr['%'] = 0;
            
            for (i = 'A'; i <= 'z'; alphptr[i++] = 0) ;
            
            symlen = PSIZE;
            s = &partition[symlen] - 256;
            tryfast = 0;

            ssvn_system_update ();
            ssvn_job_update ();
            ssvn_routine_update ();

#if defined(HAVE_MWAPI_MOTIF)
            ssvn_display_update ();
#endif

            const_restore ();
            
            return;




        case kill_sym:			/* kill them dirty bloody variables */


            /* Old Kill Routine */ 

            if ((i = alphptr[(int) key[0]]) == 0) return;			/* damn - nothing to kill */
            
            kill_from = 0;
            
            while (i < PSIZE) {

                j = i;
                k = 0;
                
                while ((k1 = key[k]) == partition[++j]) {	/* compare keys */
                    
                    if (k1 == EOL) break;
                
                    k++;

                }

                if (k1 == EOL && (partition[j] == DELIM || partition[j] == EOL)) {
                    
                    if (kill_from == 0) kill_from = i;

                } 
                else {
                    if (kill_from) break;
                }

                i += UNSIGN (partition[i]);	/* skip key */
                i += UNSIGN (partition[i]) + 1;	/* skip data */
            
            }

k_entry:			/* entry from killone section */


            if (kill_from) {

                j = i - kill_from;
                symlen += j;
                s = &partition[symlen] - 256;
                
                for (k = 36; k < key[0]; k++) {
                    if (alphptr[k]) alphptr[k] += j;
                }

                if (alphptr[k] == kill_from) {

                    alphptr[k] = i;
                    
                    if (partition[i + 1] != key[0]) alphptr[k] = 0;

                } 
                else {
                    alphptr[k] += j;
                }

                /*         j=i-j; while(i>symlen) partition[--i]=partition[--j];  */
                stcpy1 (&partition[i - 1], &partition[i - j - 1], i - symlen);

            }

            tryfast = 0;
            
            return;


        /* end of kill_sym section */

        case killone:			/* kill one variable, not descendants */


            if ((i = alphptr[(int) key[0]]) == 0) return;			/* nothing to kill */
            
            kill_from = 0;
            
            while (i < PSIZE) {

                j = i;
                k = 0;
                
                while ((k1 = key[k]) == partition[++j]) {	/* compare keys */
                    
                    if (k1 == EOL) break;

                    k++;

                }

                k = i;
                i += UNSIGN (partition[i]);	/* skip key */
                i += UNSIGN (partition[i]) + 1;	/* skip data */
                
                if (k1 == EOL) {

                    if (partition[j] == DELIM) return;		/* descendant */
                
                    kill_from = k;
                    
                    goto k_entry; 
                
                }

            }

            tryfast = 0;
            
            return;

        
        /* end of killone section */

        case killexcl:			/* exclusive kill */


            i = symlen;

            while (i < PSIZE) {

                tmp2[0] = SP;
                kill_from = i;
                
                stcpy (tmp3, &partition[i + 1]);
                stcpy (&tmp2[1], tmp3);
                stcat (tmp2, " \201");
                
                i += UNSIGN (partition[i]);
                i += UNSIGN (partition[i]) + 1;
                
                if (kill_ok (key, tmp2) == 0) continue;		/* don't kill */

                while (i < PSIZE) {

                    j = i;
                    k = 0;
                    
                    while ((k1 = tmp3[k]) == partition[++j]) {	/* compare keys */
                        
                        if (k1 == EOL) break;
                        
                        k++;
                    
                    }
                    
                    if (k1 != EOL || (partition[j] != DELIM && partition[j] != EOL)) break;
                    
                    i += UNSIGN (partition[i]);	/* skip key */
                    i += UNSIGN (partition[i]) + 1;		/* skip data */

                }

                j = i - kill_from;
                symlen += j;
                s = &partition[symlen] - 256;
                
                for (k = 36; k < tmp3[0]; k++) {
                    if (alphptr[k]) alphptr[k] += j;
                }

                if (alphptr[k] == kill_from) {
                    
                    alphptr[k] = i;
                    
                    if (partition[i + 1] != tmp3[0]) alphptr[k] = 0;

                } 
                else {
                    alphptr[k] += j;
                }

                stcpy1 (&partition[i - 1], &partition[i - j - 1], i - symlen);
                
                i = kill_from + j;
            
            }
            
            tryfast = 0;
            
            return;

            /* end of killexcl section */

        case fra_query:			/* next entry */
        case bigquery:


            if (ordercnt == 0) {

                l_o_val[0] = EOL;
                
                zname (data, key + stlen (i_with));
		
                return;

            }

            /***************************/
            /* frequent special case: the key which we search for is the next
            * entry */

            if ((i = alphptr[(int) key[0]])) {

                if (stcmp (key, &partition[tryfast + 1]) == 0) {
                    i = tryfast;
                }
                else {
                    
                    j = i;
                
                    do {

                        if (stcmp (key, &partition[j + 1]) == 0) {
                            i = j;
                            break;
                        }
                        
                        j += UNSIGN (partition[j]);		/* skip key */
                        j += UNSIGN (partition[j]) + 1;	/* skip data */

                    } while (j < PSIZE);
                
                }
            } 
            else {
                i = symlen;			/* no previous entry */
            }
            /***************************/


            /* check whether the key has subscripts or not */
            k1 = 0;
            k = 1;

            while (key[k] != EOL) {
                
                if (key[k++] == DELIM) {
                    k1 = k;
                    break;
                }

            }

            while (i < PSIZE) {

                j = i;
                k = 0;
                
                while (key[k] == partition[++j]) {	/* compare keys */
                    
                    if (key[k] == EOL) break;
                    
                    k++;
                
                }

                if (key[k] == EOL) {

                    if (partition[j] == EOL) {
                        i += UNSIGN (partition[i]);
                        i += UNSIGN (partition[i]) + 1;
                    }

                    break;

                }

                if (k < k1 || k1 == 0) {
                
                    if (key[k] < partition[j]) break;
                
                } 
                else {
                    long    m, n, o, ch;
                    
                    /* get complete subscripts */
                    n = k;
                    
                    while (key[--n] != DELIM) ;
                    
                    n++;
                    m = j + n - k;
                    o = 0;
                    
                    while ((ch = tmp2[o++] = key[n++]) != EOL && ch != DELIM) ;
                    
                    if (ch == DELIM) tmp2[--o] = EOL;

                    o = 0;
 
                    while ((ch = tmp3[o++] = partition[m++]) != EOL && ch != DELIM) ;
 
                    if (ch == DELIM) tmp3[--o] = EOL;

                    if (collate (tmp2, tmp3)) break;

                }

                i += UNSIGN (partition[i]);	/* skip key */
                i += UNSIGN (partition[i]) + 1;	/* skip data */

            }

            /* multiple backward query */
            if (ordercnt < 0) {

                j = symlen;
                k = ordercnt - 1;
                
                while (j < i) {		/* count entries */
                    
                    j += UNSIGN (partition[j]);	/* skip key */
                    j += UNSIGN (partition[j]) + 1;		/* skip data */

                    k++;

                }

                if (k < 0) {

                    data[0] = EOL;
                    l_o_val[0] = EOL;
                    
                    return;

                }

                i = symlen;
                
                while (--k >= 0) {
                    
                    i += UNSIGN (partition[i]);	/* skip key */
                    i += UNSIGN (partition[i]) + 1;		/* skip data */

                }

            }
            /* end: multiple backward query */

            while (--ordercnt > 0) {	/* multiple forward $query */
                
                if (i >= PSIZE) break;

                i += UNSIGN (partition[i]);	/* skip key */
                i += UNSIGN (partition[i]) + 1;	/* skip data */

            }

            /* now 'i' is pointer to 'next' entry */
            tryfast = i;

            /* save data value for inspection with $V(110) */
            j = i;

            j += UNSIGN (partition[j]);
            k = UNSIGN (partition[j]);

            stcpy0 (l_o_val, &partition[j + 1], k);
            l_o_val[k] = EOL;
            
            keyl = i;
            keyl += UNSIGN (partition[i++]) - 2;

            /* action==bigquery may return a result in a different lvn */
            /* which is illegal with $query() */
            if (action == fra_query) {

                k = 0; /* is result same lvn? */
                
                while (partition[i+k] == key[k]) {
                    
                    if (key[k] == DELIM) break;
                
                    k++;

                }

                if (partition[i+k] != DELIM) i = keyl + 1; /* discard result! */
            
            }
            
            if (i <= keyl) {
                zname (data, &partition[i + stlen (i_with)]);		
            }
            else {
                data[0] = EOL;
            }
            
            return;
/* end of $query section */

zinv:				/* previous one please */
            
            data[0] = EOL;
            l_o_val[0] = EOL;
            
            k1 = (j = stcpy (tmp1, key) - 1);
            
            while (tmp1[k1] != DELIM) {
                
                if ((--k1) <= 0) {
                    merr_raise (NEXTER);
                    return;
                }

            }

            tmp1[++k1] = EOL;
            
            stcpy (tmp2, &key[k1]);
            
            if (tmp2[0] == EOL) {
                
                tmp2[0] = DEL;
                tmp2[1] = DEL;
                tmp2[2] = EOL;

            }

            k = (int) (key[0]);
            
            if (alphptr[k] == 0) return;
            
            j = alphptr[k];
            
            do {

                if (key[0] != partition[j + 1]) goto zinvend;

                stcpy0 (tmp3, &partition[j + 1], k1);
                
                tmp3[k1] = EOL;

                if (stcmp (tmp1, tmp3) == 0) {
                    
                    stcpy (tmp3, &partition[j + 1 + k1]);	/* index on same level */
                    
                    k = 0;
                    
                    while (tmp3[k] != EOL && tmp3[k] != DELIM) k++;

                    tmp3[k] = EOL;
                    
                    if (collate (tmp3, tmp2) == FALSE) goto zinvend;
                    
                    stcpy (data, tmp3);
                    
                    /* save data value for inspection with $V(110) */
                    i = j;
                    
                    i += UNSIGN (partition[i]);
                    k = UNSIGN (partition[i]);
                    
                    stcpy0 (l_o_val, &partition[i + 1], k);
                    
                    l_o_val[k] = EOL;

                }

                j += UNSIGN (partition[j]);	/* skip key */
                j += UNSIGN (partition[j]) + 1;	/* skip data */

            } while (j < PSIZE);

zinvend:

            if (data[0] == EOL) return;

            ordercounter++;
            
            if (++ordercnt >= 0) return;
            
            stcpy (&key[k1], data);
            
            goto zinv;





        /* end of $zinverse section */
        

        case new_sym:			/* new one symbol */

            if (key[0] == '$') {		/* $svn: save current value on new stack */



                if (newptr > newlimit && getnewmore ()) return;

                if ((key[1] | 0140) == 't') {	/* NEW $TEST */
                    
                    *newptr++ = test;
                    *newptr++ = EOL;
                    *newptr++ = 1;
                    
                    k1 = stcpy (newptr, "$t\201");
                    
                    newptr += k1;
                    *newptr++ = EOL;
                    *newptr++ = k1;
                    *newptr++ = set_sym;
                    
                    //if (mcmnd != ZNEW) test = FALSE;

                    return;

                }

                if ((key[1] | 0140) == 'j') {	/* NEW $JOB */

                    *newptr++ = pid / 256;
                    *newptr++ = pid % 256;
                    *newptr++ = EOL;
                    *newptr++ = 2;
                    
                    k1 = stcpy (newptr, "$j\201");
                    
                    newptr += k1;
                    *newptr++ = EOL;
                    *newptr++ = k1;
                    *newptr++ = set_sym;
                    
                    return;

                }

                if (((key[1] | 0140) == 'z') &&	((key[2] | 0140) == 'i')) { /* NEW $ZINRPT */
                    
                    *newptr++ = breakon;
                    *newptr++ = EOL;
                    *newptr++ = 1;
                    
                    k1 = stcpy (newptr, "$zi\201");
                    
                    newptr += k1;
                    *newptr++ = EOL;
                    *newptr++ = k1;
                    *newptr++ = set_sym;
                    
                    return;
                
                }


                /* NEW $ETRAP added 10 Oct 2020, JPW */
                if (((key[1] | 0140) == 'e') && ((key[2] | 0140) == 't')) { /* NEW $ETRAP */
                    
                    j = stcpy (newptr, etrap);

                    newptr += j;
                    *newptr++ = EOL;
                    *newptr++ = j;

                    k1 = stcpy (newptr, "$et\201");

                    newptr += k1;
                    *newptr++ = EOL;
                    *newptr++ = k1;
                    *newptr++ = set_sym;
                                       
                    return;
                
                }

                /* NEW $ESTACK added 12 Oct 2020, JPW */
                if (((key[1] | 0140) == 'e') && ((key[2] | 0140) == 's')) { /* NEW $ESTACK */
                    
                    char esbuf[256];

                    snprintf (esbuf, 255, "%d\201", estack);

                    j = stcpy (newptr, esbuf);

                    newptr += j;
                    *newptr++ = EOL;
                    *newptr++ = j;

                    k1 = stcpy (newptr, "$es\201");

                    newptr += k1;
                    *newptr++ = EOL;
                    *newptr++ = k1;
                    *newptr++ = set_sym;

                    estack = 0;
                                       
                    return;
                
                }

                j = stcpy (newptr, zref);	/* NEW $ZREFERENCE */
                
                newptr += j;
                *newptr++ = EOL;
                *newptr++ = j;
                
                k1 = stcpy (newptr, "$zr\201");
                
                newptr += k1;
                *newptr++ = EOL;
                *newptr++ = nakoffs;
                
                k1++;
                
                *newptr++ = k1;
                *newptr++ = set_sym;
                
                if (mcmnd != ZNEW) zref[0] = EOL;

                return;


            }



            if ((i = alphptr[(int) key[0]])) {	/* is there something to be saved?/killed */
                
                /* always FALSE with special variables    */ 
                kill_from = 0;
                
                while (i < PSIZE) {
                    
                    j = i;
                    k = 0;
                    
                    while ((k1 = key[k]) == partition[++j]) {	/* compare keys */
                        
                        if (k1 == EOL) break;
                    
                        k++;

                    }

                    if (k1 == EOL && (partition[j] == DELIM || partition[j] == EOL)) {
                        
                        if (kill_from == 0) kill_from = i;

                    } 
                    else {
                        if (kill_from) break;
                    }

                    if (kill_from) {	/* save current values on new stack */
                        
                        j = UNSIGN (partition[i]);                        
                        k = i + 1;
                        k1 = j;
                        i += j;
                        j = UNSIGN (partition[i]);

                        if (newptr > newlimit && getnewmore ()) return;
                        
#ifdef DEBUG_SYM

                        start = newptr;

#endif

                        stcpy0 (newptr, &partition[i + 1], j);

                        newptr += j;
                        *newptr++ = EOL;
                        *newptr++ = j;
                        
                        i += (j + 1);
                        
                        stcpy0 (newptr, &partition[k], k1);
                        
                        newptr += k1;
                        *newptr++ = EOL;
                        *newptr++ = k1;
                        *newptr++ = set_sym;
                        
#ifdef DEBUG_SYM

                        printf ("SAVING [newptr] newptr became [");

                        while (start < newptr) { 
                        
                            printf ("%c(%d)", (*start==EOL) ? ('!') : *start, *start); 
                        
                            start++; 
                        
                        }
                        
                        printf("{%d}]\r\n", *(newptr - 1));

#endif
                    
                    } 
                    else {
                        
                        i += UNSIGN (partition[i]);		/* skip key */
                        i += UNSIGN (partition[i]) + 1;	/* skip data */

                    }

                }

                if (kill_from && mcmnd != ZNEW) {

                    j = i - kill_from;
                    symlen += j;
                    s = &partition[symlen] - 256;
                    
                    for (k = 36; k < key[0]; k++) {                    
                        if (alphptr[k]) alphptr[k] += j;                    
                    }

                    if (alphptr[k] == kill_from) {

                        alphptr[k] = i;
                        
                        if (partition[i + 1] != key[0]) alphptr[k] = 0;
                    
                    } 
                    else {
                        alphptr[k] += j;
                    }

                    stcpy1 (&partition[i - 1], &partition[i - j - 1], i - symlen);

                }

                tryfast = 0;
            
            }

            if (newptr > newlimit && getnewmore ()) return;
            
#ifdef DEBUG_SYM
            start = newptr;
#endif

            j = stcpy (newptr, key);

            newptr += j;
            *newptr++ = EOL;
            *newptr++ = j;
            *newptr++ = kill_sym;
            
#ifdef DEBUG_SYM

            printf ("KILLING [newptr] newptr became [");
            
            while (start < newptr) {                 
                printf ("%c(%d)", (*start == EOL) ? ('!') : *start,*start ); 
                
                start++; 

            }

            printf ("{%d}]\r\n", *(newptr - 1));

#endif

            return;

        /* end of new_sym section */
        

        case new_all:			/* new all symbols */



            i = symlen;
            
            while (i < PSIZE) {

                j = UNSIGN (partition[i]);
                k = i + 1;
                k1 = j;
                i += j;
                j = UNSIGN (partition[i]);
                
                if (newptr > newlimit && getnewmore ()) return;

                stcpy0 (newptr, &partition[i + 1], j);
                
                newptr += j;
                *newptr++ = EOL;
                *newptr++ = j;
                i += (j + 1);
                
                stcpy0 (newptr, &partition[k], k1);
                
                newptr += k1;
                *newptr++ = EOL;
                *newptr++ = k1;
                *newptr++ = set_sym;

            }
            
            *newptr++ = kill_all;
            
            if (mcmnd == ZNEW) return;
            
            goto genocid;			/* ... and now kill them all */

        /* end of new_all section */


        case newexcl:			/* new all except specified */



            i = symlen;

            while (i < PSIZE) {

                tmp2[0] = SP;
                kill_from = i;
                
                stcpy (tmp3, &partition[i + 1]);
                stcpy (&tmp2[1], tmp3);
                stcat (tmp2, " \201");
                
                if (kill_ok (key, tmp2) == 0) {	/* don't new */

                    i += UNSIGN (partition[i]);
                    i += UNSIGN (partition[i]) + 1;
                
                    continue;
                
                }
                
                j = UNSIGN (partition[i]);
                k = i + 1;
                k1 = j;
                i += j;
                j = UNSIGN (partition[i]);
                
                if (newptr > newlimit && getnewmore ()) return;

                stcpy0 (newptr, &partition[i + 1], j);
                
                newptr += j;
                *newptr++ = EOL;
                *newptr++ = j;
                i += (j + 1);
                
                stcpy0 (newptr, &partition[k], k1);
                
                newptr += k1;
                *newptr++ = EOL;
                *newptr++ = k1;
                *newptr++ = set_sym;

                while (i < PSIZE) {
                    
                    j = i;
                    k = 0;
                    
                    while ((k1 = tmp3[k]) == partition[++j]) {	/* compare keys */
                        
                        if (k1 == EOL) break;
                    
                        k++;

                    }

                    if (k1 != EOL || (partition[j] != DELIM && partition[j] != EOL)) break;

                    j = UNSIGN (partition[i]);
                    k = i + 1;
                    k1 = j;
                    i += j;
                    j = UNSIGN (partition[i]);

                    if (newptr > newlimit && getnewmore ()) return;

                    stcpy0 (newptr, &partition[i + 1], j);
                    
                    newptr += j;
                    *newptr++ = EOL;
                    *newptr++ = j;
                    i += (j + 1);
                    
                    stcpy0 (newptr, &partition[k], k1);
                    
                    newptr += k1;
                    *newptr++ = EOL;
                    *newptr++ = k1;
                    *newptr++ = set_sym;

                }
                
                if (mcmnd == ZNEW) continue;

                j = i - kill_from;
                symlen += j;
                s = &partition[symlen] - 256;

                for (k = 36; k < tmp3[0]; k++) {
                    
                    if (alphptr[k]) alphptr[k] += j;

                }

                if (alphptr[k] == kill_from) {
                    
                    alphptr[k] = i;
                    
                    if (partition[i + 1] != tmp3[0]) alphptr[k] = 0;

                } 
                else {
                    alphptr[k] += j;
                }

                stcpy1 (&partition[i - 1], &partition[i - j - 1], i - symlen);
                
                i = kill_from + j;
            
            }
            
            tryfast = 0;
            
            if (newptr > newlimit && getnewmore ()) return;

            j = stcpy (newptr, key);
            
            newptr += (j + 1);
            *newptr++ = j;
            *newptr++ = killexcl;
            
            return;


        /* end of newexcl section */

        
        case m_alias:			/* define an alias of a variable */


            /* process stuff */
            if (stcmp (key, data) == 0) return;			/* sorry, that's no alias */
            
            if (data[0] == EOL) {		/* delete an alias from the table */
                
                if (aliases) {		/* there are aliases */

                    i = 0;
                    
                    while (i < aliases) {

                        k = i;
                        k1 = i + UNSIGN (ali[i]) + 1;
                        j = 0;		/* is current reference an alias ??? */
                        
                        while (ali[++i] == key[j]) {
                            
                            if (ali[i] == EOL) break;

                            j++;

                        }

                        /* yes, it is, so resolve it now! */
                        if (ali[i] == EOL && key[j] == EOL) {

                            if (aliases > k1) stcpy0 (&ali[k], &ali[k1], aliases - k1);

                            aliases -= (k1 - k);
                            
                            return;

                        }

                        i = k1;

                    }

                }

                return;

            }

            /* new entry to alias table. there is no check agains duplicate entries */
            i = stlen (key);
            j = stlen (data);
            
            ali[aliases++] = (char) (i + j + 2);	/* byte for fast skipping */            
            
            stcpy (&ali[aliases], key);            
            aliases += (i + 1);
            
            stcpy (&ali[aliases], data);
            aliases += (j + 1);

            /* write note to unmake the alias */
            j = stcpy (newptr, key);
            newptr += (j + 1);
            *newptr++ = j;
            *newptr++ = m_alias;

            return;

        case zdata:			/* nonstandard data function */


            
            {
                long counties[128];
                int icnt, icnt0;

                i = 0;

                while (i < 128) counties[i++] = 0L;	/* init count;  */
                
                /* note: we assume EOL<DELIM<ASCII */
                
                icnt = 0;
                i = 0;
                
                while ((j = key[i++]) != EOL) {
                    if (j == DELIM) {
                        icnt++;
                    }
                }

                if ((i = alphptr[(int) key[0]])) {

                    data[2] = EOL;
                    j = i + 1;
                    k = 1;
                    
                    do {

                        icnt0 = j + 1;
                        
                        while ((k1 = key[k] - partition[++j]) == 0) {	/* compare keys */
                            
                            if (key[k] == EOL) break;

                            k++;

                        }                        

                        if (k1 == 0) {
                            counties[0] = 1;
                        }
                        else {

                            if (partition[j] == DELIM && key[k] == EOL) {
                                
                                int ch;

                                j = icnt0;
                                icnt0 = 0;
                                
                                while ((ch = partition[j++]) != EOL) {
                                    
                                    if (ch == DELIM) {
                                        icnt0++;
                                    }

                                }
                                
                                if (icnt0 <= icnt) break;

                                counties[icnt0 - icnt]++;

                            }

                            /*                  if (k1<0 && k<2) break;     */
                        
                        }
                        
                        i += UNSIGN (partition[i]);		/* skip key */
                        i += UNSIGN (partition[i]) + 1;	/* skip data */
                        
                        j = i;
                        k = 0;

                    } while (i < PSIZE);

                }

                i = 128;
                
                while (counties[--i] == 0L) ;
                
                lintstr (data, counties[0]);
                
                j = 1;
                tmp1[0] = ',';
                
                while (j <= i) {
                
                    lintstr (&tmp1[1], counties[j++]);
                    stcat (data, tmp1);

                }

                return;
            }				/* end of $zdata section */

    }					/* end of action switch */


/* return next variable or array name - non standard */
unsubscr:

    if (standard) {
        merr_raise (NEXTER);
        return;
    }

    j = key[0];
    data[0] = EOL;

    while (alphptr[j] == 0) {
        if (++j >= DEL) return;
    }

    i = alphptr[j];
    
    while (i < PSIZE) {
        
        j = i;
        k = 0;
        
        while ((k1 = key[k] - partition[++j]) == 0) {	/* compare keys */
            
            if (key[k] == EOL) break;
        
            k++;
        
        }

        if (k1 < 0 && (partition[j] != DELIM || key[k] != EOL)) {
            
            j = i;
            i = 0;
            
            while ((data[i] = partition[++j]) != EOL) {
                
                if (data[i] == DELIM) {
                    data[i] = EOL;
                    break;
                }
                
                i++;

            }

            return;

        }

        i += UNSIGN (partition[i]);	/* skip key */
        i += UNSIGN (partition[i]) + 1;	/* skip data */

    }

    return;

}					/* end of symtab() */


/******************************************************************************/
    /* if 't' follows 's' in MUMPS collating sequence a 1 is returned
     * otherwise 0
     */

short int collate (char *s, char *t)
{
    short dif;

    if (s[0] == EOL) return (t[0] != EOL);		/* the empty one is the leader! */
    if (t[0] == EOL) return FALSE;
    if ((dif = stcmp (t, s)) == 0) return FALSE;
    
    if (numeric (s)) {			/* then come numerics */
        
        if (numeric (t) == FALSE) return TRUE;
    
        return comp (s, t);

    }

    if (numeric (t)) return FALSE;

    return dif > 0;

}					/* end of collate() */

/******************************************************************************/
short int numeric (char *str)
    /**
     *  boolean function that tests
     *  whether str is a canonical
     *  numeric
     */
{
    register int ptr = 0, ch;
    register int point;


    
    if (str[0] == '-') {
        ptr = 1;
    }
    if (str[ptr] == EOL) {
        return FALSE;
    }
    if (str[ptr] == '0') return str[1] == EOL;		/* leading zero */
    
    point = FALSE;

    while ((ch = str[ptr++]) != EOL) {

        
        if (ch > '9') {
            return FALSE;
        }
        
        if (ch < '0') {

            if (ch != '.') return FALSE;
            if (point) return FALSE;		/* multiple points */
        
            point = TRUE;
        
        }

    }

    if (point) {

        if ((ch = str[ptr - 2]) == '0') return FALSE;		/* trailing zero */
        if (ch == '.') return FALSE;		/* trailing point */
    }
    return TRUE;
}					/* end of numeric() */

/******************************************************************************/
    /* s and t are strings representing */
    /* MUMPS numbers. comp returns t>s  */

short int comp (char *s, char *t)
{

    register int s1 = s[0], t1 = t[0], point = '.';

#if !defined(_AIX)    
    if (fp_mode) {
        double fp_s;
        double fp_t;

        stcnv_m2c (s);
        stcnv_m2c (t);

        fp_s = atof (s);
        fp_t = atof (t);

        return fp_t > fp_s;
    }
#endif    
    
    if (s1 != t1) {

        if (s1 == '-') return TRUE;		/* s<0<t */
        if (t1 == '-') return FALSE;		/* t<0<s */
        if (s1 == point && t1 == '0') return FALSE;		/* s>0; t==0 */
        if (t1 == point && s1 == '0') return TRUE;		/* t>0; s==0 */

    }

    if (t1 == '-') {
    
        char *a;

        a = &t[1];
        t = &s[1];
        s = a;

    }

    s1 = 0;
    
    while (s[s1] > point) s1++;				/* Note: EOL<'.' */
    
    t1 = 0;
    
    while (t[t1] > point) t1++;

    if (t1 > s1) return TRUE;
    if (t1 < s1) return FALSE;
    
    while (*t == *s) {

        if (*t == EOL) return FALSE;
    
        t++;
        s++;
    
    }

    if (*t > *s) return TRUE;
    
    return FALSE;

}					/* end of comp() */
/******************************************************************************/
void intstr (char *str, short integ)			/* converts integer to string */
{

    if (integ < 0) {
        integ = (-integ);
        *str++ = '-';
    }

    if (integ < 10) {

        *str++ = integ + '0';
        *str = EOL;
        
        return;

    } 
    else if (integ < 100) {
        str += 2;
    } 
    else if (integ < 1000) {
        str += 3;
    } 
    else if (integ < 10000) {
        str += 4;
    } 
    else {
        str += 5;
    }

    *str = EOL;
    
    do {
        *(--str) = integ % 10 + '0';
    } while (integ /= 10);
    
    return;
}					/* end of intstr() */

/******************************************************************************/
void lintstr (char *str, long integ)			/* converts long integer to string */
{
    char result[11];			/* 32 bit = 10 digits+sign */
    register int i = 0;

    if (integ < 0) {
        integ = (-integ);
        *str++ = '-';
    }

    do {
        result[i++] = integ % 10 + '0';
    } while (integ /= 10);
    
    do {
        *str++ = result[--i];
    } while (i > 0);
    
    *str = EOL;
    
    return;

}					/* end of lintstr() */

/****************************************************************/

/* user defined special variable table management */
/* The symbol table is placed at the high end of 'svntable'. It begins at
 * 'svnlen' and ends at 'UDFSVSIZ'. The layout is
 * (keylength)(key...)(<EOL>)(datalength)(data...[<EOL>])
 * The keys are sorted in alphabetic sequence.
 * 
 * To have the same fast access regardless of the position in the
 * alphabet for each character a pointer to the first variable beginning
 * with that letter is maintained. (0 indicates there's no such var.)
 */

void udfsvn (short action, char *key, char *data)		/* symbol table functions */
{

long keyl;			/* length of key                  */
long datal;			/* length of data                 */
register long int i, j, k, k1;



#ifdef DEBUG_SYM
    
    char *start;

#endif

    switch (action) {


        case get_sym:			/* retrieve */


            if ((i = svnaptr[(int) key[0]])) {

                k = 1;
                j = i + 1;			/* first char always matches! */

                do {

                    while (key[k] == svntable[++j]) {	/* compare keys */
                        
                        if (key[k++] == EOL) {
                            
                            i = UNSIGN (svntable[++j]);
                            stcpy0 (data, &svntable[j + 1], i);
                            data[i] = EOL;
                        
                            return;
                        }

                    }

                    i += UNSIGN (svntable[i]);	/* skip key */
                    i += UNSIGN (svntable[i]) + 1;	/* skip data */
                    
                    k = 0;
                    j = i;

                } while (i < UDFSVSIZ);

            }
            
            merr_raise (ILLFUN);            
            return;


        case set_sym:			/* store/create variable; */


            if ((keyl = stlen (key) + 2) > STRLEN) {
                merr_raise (M75);
                return;
            }				/* key length +2 */
            
            datal = stlen (data);		/* data length */

            if ((i = svnaptr[(int) key[0]])) {	/* previous entry */
                
                j = i + 1;
                k = 1;

            } 
            else {
                
                i = svnlen;
                j = i;
                k = 0;

            }

            while (i < UDFSVSIZ) {		/* compare keys */
                
                while (key[k] == svntable[++j]) {
                    
                    if (key[k] == EOL) goto old;
                    
                    k++;
                
                }
                
                if (key[k] < svntable[j]) break;
                
                i += UNSIGN (svntable[i]);	/* skip key */
                i += UNSIGN (svntable[i]) + 1;	/* skip data */
                j = i;
                k = 0;

            }

            /* if    entry found,     i pointer to searched entry
            * else  entry not found, i pointer to alphabetically next entry */
            /* new entry */
            
            k = i;
            j = key[0];
            i = keyl + datal + 1;
            
            if (svnlen <= i) {

                long dif;

                dif = getumore ();
                
                if (dif == 0L) return;
                
                k += dif;

            }

            for (k1 = 'a'; k1 <= j; k1++) {
                if (svnaptr[k1]) svnaptr[k1] -= i;
            }

            i = k - i;
            
            if (svnaptr[j] == 0 || svnaptr[j] > i) svnaptr[j] = i;

            i = (svnlen -= (j = keyl + datal + 1));            
            stcpy0 (&svntable[i], &svntable[j + i], k - i);            

            i = k - (keyl + datal + 1);
            svntable[i++] = (char) (keyl);            
            stcpy (&svntable[i], key);	/* store new key */
            
            i += keyl - 1;
            svntable[i++] = (char) (datal);
            stcpy0 (&svntable[i], data, datal);	/* store new data */
            
            return;

            /* there is a previous value */
old:

            i += UNSIGN (svntable[i]);
            j = UNSIGN (svntable[i]) - datal;
            
            if (j < 0) {			/* more space needed */
                
                if (svnlen <= (-j)) {
                    
                    long dif;

                    dif = getumore ();
                    
                    if (dif == 0L) return;

                    i += dif;

                }

                svnlen += j;
                
                for (k = 'a'; k < key[0]; k++) {
                    if (svnaptr[k]) svnaptr[k] += j;
                }

                if (svnaptr[k] && svnaptr[k] < i) svnaptr[k] += j;
                
                k = i + j;
                i = svnlen;
                stcpy0 (&svntable[i], &svntable[i - j], k - i);
                
                i = k;
            
            } 
            else if (j > 0) {		/* surplus space */
               
                svnlen += j;
                
                for (k = 'a'; k < key[0]; k++) {
                    if (svnaptr[k]) svnaptr[k] += j;
                }

                if (svnaptr[k] && svnaptr[k] < i) svnaptr[k] += j;
                
                i += j;
                k = i;
                j = i - j;
                
                while (i >= svnlen) {
                    svntable[i--] = svntable[j--];
                }

                i = k;

            }

            svntable[i++] = (char) (datal);
            
            stcpy0 (&svntable[i], data, datal);	/* store new data */
            
            return;
            /* end of set_sym section */
        }
}					/* end user defined special variable table */


/******************************************************************************/
long getpmore (void)
{					/* try to get more 'partition' space. returns size increment */
    
    long siz;
    long dif;

    if (autopsize == FALSE) return 0L;
    
    siz = PSIZE;
    
    if (siz % 1024) siz = (siz & ~01777) + 02000;	/* round for full kB; */
    
    siz += 01777;
    dif = siz - PSIZE;
    
    if (newpsize (siz)) return 0L;
    
    return dif;

}					/* end getpmore */

/******************************************************************************/
long getumore (void)
{					/* try to get more udfsvntab space. returns size increment */
    long siz, dif;

    if (autousize == FALSE) {
        merr_raise (STORE);
        return 0L;
    }

    siz = UDFSVSIZ;
    
    if (siz % 1024) siz = (siz & ~01777) + 02000;	/* round for full kB; */
    
    siz += 01777;
    dif = siz - UDFSVSIZ;
    
    if (newusize (siz)) {
        merr_raise (STORE);
        return 0L;
    }

    return dif;

}					/* end getumore */

/******************************************************************************/
long getrmore (void)
{					/* try to get more routine space. returns size increment */
    long siz, dif;
    short i;

    if (autorsize == FALSE) {
        merr_raise (PGMOV);
        return 0L;
    }
    
    siz = PSIZE0;
    
    if (siz % 1024) siz = (siz & ~01777) + 02000;	/* round for full kB; */
    
    siz += 01777;
    dif = siz - PSIZE0;
    
    for (i = 0; i < NO_OF_RBUF; i++) {	/* empty routine buffer */
        pgms[i][0] = EOL;
        ages[i] = 0L;
    }

    if (newrsize (siz, NO_OF_RBUF)) {
        merr_raise (PGMOV);
        return 0L;
    }

    return dif;

}					/* end getrmore */

/******************************************************************************/
short int getnewmore (void)
{					/* enlarge new_buffers */
    char *newbuf;
    int i;
    long dif;

    newbuf = calloc ((unsigned) (NSIZE + 4096), 1);	/* new_buffer                      */
    
    if (newbuf == NULL) {		/* could not allocate stuff...     */
        merr_raise (STKOV);
        return 1;
    }

    stcpy0 (newbuf, newstack, (long) NSIZE);
    
    dif = newbuf - newstack;
    
    free (newstack);			/* free previously allocated space */
    
    newstack = newbuf;
    NSIZE += 4096;
    newptr += dif;
    newlimit = newstack + NSIZE - 1024;
    i = 0;

    while (i <= nstx) {
        
        if (nestnew[i]) nestnew[i] += dif;
        
        i++;

    }

    return 0;

}					/* end getnewmore() */
/******************************************************************************/



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